自定义拖拽面板angular7_angular实现draggable拖拽

前言:最近项目要实现一个拖拽功能,我在网上开始了各类搜寻,虽然后面因为数据原因舍弃了拖拽的这一需求,但是为了不辜负最近的研究,还是来记录一下。

场景需求:面试预约选时间节点,候选人之间是可以相互交换的,但是局限于面试方向相同的候选人才能相互拖拽(拖拽后即表示两个候选人之间交换面试时间)。本来此种场景上图更为明确,奈何公司只限于内网开发,上传不了图片,嘤嘤嘤。。。

正文:

draggable是H5新增的属性,true表示可以拖拽,false表示不能拖拽。在拖拽过程中分别有两个元素:被拖动元素与目标元素。

被拖动元素相关的事件:

ondragstart:按下鼠标并开始移动时触发该事件。

ondrag:在start事件触发后被触发,并在鼠标移动过程中不停被触发。

ondragend:当拖动停止触发(无论把元素放到拖放目标上还是在无效目标上)

目标元素相关的事件:

ondragenter:被拖动元素进入目标时触发。

ondragover:被拖动元素在目标元素上移动时被触发。

ondragleave:被拖动元素离开目标时触发,即拖到无效目标时。

ondrop:被拖动元素被放置在目标上时被触发。

注意:默认情况下目标元素是不允许被放置的,所以不会触发drop事件。这时需要在ondragover中阻止默认行为才能成为被允许放置的目标。

对于angular、vue等依赖组件开发的框架,最好把draggable封装成指令去实现功能。(实施步骤与参考文章无异,直接上代码啦,其他不赘述)具体步骤:

1.新建directives指令文件夹

2.新建拖拽文件夹directives/drap-drop

3.新建drap指令文件directives/drag-drop/drag.directive.ts

4.新建drop指令文件directives/drag-drop/drop.directive.ts

5.因为涉及数据交换,所以要新建一个services来传递数据,directives/directives.services.ts

6.新建directives/directives.module.ts

7.在公共模板中引入DirectiveModule

8.引用

directives.module.ts

import { NgModule } from '@angular/core';

import { DragDirective } from'./drag-drop/drag.directive';

import { DropDirective } from'./drag-drop/drop.directive';

import { DragDropService } from'./drag-drop/drag-drop.service';

@NgModule({

declarations: [DragDirective, DropDirective],

exports: [DragDirective, DropDirective],

providers:[DragDropService]

})

export class DirectiveModule { }

drag.directive.ts

import { Directive,HostBinding, HostListener, Host, ElementRef, Renderer2, Input,Output,EventEmitter } from '@angular/core';

import {DragDropService} from'./drag-drop.service';

@Directive({

selector:'[app-draggable][dragTag][dragData][draggedClass]'})

export class DragDirective {

private _isDraggble= false;/*给标签设置draggable属性

*true-能拖拽

*false-不能拖拽*/@Input('app-draggable')

set isDraggable(value:boolean){this._isDraggble=value;this.rd.setAttribute(this.el.nativeElement,'draggable',`${value}`);

}

get isDraggable(){return this._isDraggble;

}//拖拽开始时添加的class

@Input()

draggedClass:string;//给拖拽的元素定义dragTag标识(目标元素也会设置一个标识,用于判断该元素是否能拖到目标元素)

@Input()

dragTag:any;//给DragDropservice传递的数据(即目标元素的数据)

@Input()

dragData:any//判断开始/结束拖拽时,部分区域的元素是不能设置为拖拽目标的(给不能拖拽的区域设置背景色)

@Output()

dragStart= new EventEmitter();

@Output()

dragEnd= new EventEmitter();

constructor(private el:ElementRef, private rd:Renderer2,private service:DragDropService) { }

@HostListener('dragstart', ['$event'])

ondragstart(ev:Event){//判断drag元素是不是指令应用的元素发起的

if(this.el.nativeElement===ev.target){this.rd.addClass(this.el.nativeElement, this.draggedClass);//往el上增加一个class

//进入时候给service传递上数据

this.service.setDragData({tag:this.dragTag,data:this.dragData});

ev['dataTransfer'].setData('tag',this.dragTag);//兼容firefox,用来设置拖放操作的drag data到指定的数据和类型

this.dragStart.emit(this.dragTag);

}

}

@HostListener('dragend', ['$event'])

ondragend(ev:Event){if(this.el.nativeElement===ev.target){this.rd.removeClass(this.el.nativeElement, this.draggedClass);this.dragEnd.emit(this.dragTag);

}

}

}

drop.directive.ts

import { Directive, HostListener, ElementRef, Renderer2, Input, Output, EventEmitter } from '@angular/core';

import { DragDropService, DragData } from'./drag-drop.service';

import { take } from'rxjs/operators';

@Directive({

selector:'[dropTag]'})

export class DropDirective {/*拖拽至目标元素时发射的事件*/@Output()

dropped= new EventEmitter();/*设定目标区域的标识*/@Input()

dropTag:any;

private data$;

constructor(private el:ElementRef, private rd:Renderer2,private service:DragDropService) {this.data$ = this.service.getDragData().pipe(take(1));

}

@HostListener('dragenter', ['$event'])

onDragEnter(ev:Event){//判断drag元素是不是指令应用的元素发起的

if(this.el.nativeElement===ev.target){this.data$.subscribe(dragData=>{if(dragData && this.dropTag ==dragData.tag){

}

});

}

}//dragover允许进行data transfer的一些特效

@HostListener('dragover', ['$event'])

onDragOver(ev:Event){//需要支持多级拖拽,所以要防止事件冒泡

ev.preventDefault();

ev.stopPropagation();if(this.el.nativeElement===ev.target){this.data$.subscribe(dragData=>{if(dragData && this.dropTag ==dragData.tag){this.rd.setProperty(ev,'dataTransfer.effectAllowed','all');this.rd.setProperty(ev,'dataTransfer.fropEffect','move');

}else{this.rd.setProperty(ev,'dataTransfer.effectAllowed','none');this.rd.setProperty(ev,'dataTransfer.dropEffect','none');

}

});

}

}

@HostListener('dragleave', ['$event'])

onDragLeave(ev:Event){

ev.preventDefault();

ev.stopPropagation();if(this.el.nativeElement===ev.target){this.data$.subscribe(dragData=>{if(dragData && this.dropTag ==dragData.tag){

}

});

}

}

@HostListener('drop', ['$event'])

onDrop(ev:Event){

ev.preventDefault();

ev.stopPropagation();if(this.el.nativeElement===ev.target){this.data$.subscribe(dragData =>{if(dragData && this.dropTag =

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值