前言
最近在做的需求,要求将左侧的元素拖拽到右边指定区域,并要求可以对大小位置进行拖拽缩放,刚开始一听到这个需求,刚开始想着直接用插件进行实现,后面针对业务需求自己用原生写了一套,这里记录下使用和封装过程中遇到的问题,希望能对你有点帮助。
插件实现
听到这个需求,脑子里面最快想到的插件是 vuedraggable,使用这个插件即可将左侧的元素克隆到指定画布区域,并且可支持调整顺序等,至于画布内缩放拖动,这里使用另一个插件 vue-drag-resize,使用这个插件即可对元素进行拖拽缩放,初步完成最初的效果。
克隆元素到画布
-
vuedraggable 常用属性介绍
这里使用的版本是^2.24.3,如果是以前的版本可能有点变化,具体参考 vuedraggable value:你要进行操作的元素,
Array
类型,推荐使用v-model
group:组名称,只有相同组之间互相拖拽,例如左边盒子要往右边盒子拖拽元素,必须保持两边盒子的组名称一致,才可进行拖拽。
可传递string
或Object
,如果传递string
,即可直接group="componentsGroup"
,如果是传递Object
,他有三个可选属性:name
、pull
、put
name
属性即组名称,group="componentsGroup"
等价于 :group="{name:'componentsGroup'}"
。
pull
属性定义从该组件移出去的设置,他有4个可选值true/false/'clone'/function
,true
表示可以被移出,false
表示不能被移出,clone
表示将克隆一份移出,function
可自定义是否能进行移出,通过return true or false
判断是否能被移出。
put
属性定义从该组件移入的设置,true/false/['componentsGroup']/function
,true,false,function
同上,['componentsGroup']
可以设置能从其他组件移入过来的组名称,例如:有三个盒子,左、中、右,但是我只想要中间盒子能移入左边盒子,那就在左边盒子设置这个put为:[中间盒子的组名称]
。
sort:设置当前组是否可以排序。
animation:拖动时的动画时长。
disabled:设置盒子是否能够拖动。
handle:设置只有这个指定的css才能拖动,例如一个盒子我们只想让hover按钮后才能拖动,那就设置handle=".sort"
,这个.sort
就是该按钮的class
。
ghostClass:设置拖动元素时的class
draggable:设置哪些元素能够拖动,和handle
的区别是,handle
是设置哪些元素能触发整体拖动,draggable
是设置只有哪些元素能够被拖动,例如一个盒子我们只想让hover
按钮后才能拖动整个盒子,那就用handle
,如果只想按钮能被拖动,那就设置draggable
。
start:(Function类型) 拖动开始的事件。
end:(Function类型) 拖动结束的事件。
add:(Function类型) 新增时的事件。
remove:(Function类型)移除时的时间。
clone:(Function类型) 设置pull为'clone'
后,开始拖动后触发的克隆事件。
....其他属性看官方例子
-
安装插件
npm install -s vuedraggable
or
yarn add vuedraggable
-
引入插件(推荐局部引入)
import draggable from "vuedraggable";
components: { draggable}
-
组件中使用
左侧可拖动元素:
<draggable
class="component-list"
:group="{ name: 'componentDrag', pull: 'clone' }"
:sort="false"
animation="300"
draggable=".component-item"
@end="handleEnd"
v-model="comList"
:clone="cloneComponent">
<div
v-for="(element, index) in comList"
:key="index"
class="component-item"
>
<el-icon name="circle-plus-outline" class="icon"></el-icon
>{{ element.title }}
</div>
</draggable>
data(){
return{
comList: [
{
title: "矩形盒子",
componentName: "dragBox",
id: "",
config: {
w: 150,
h: 150,
x: 0,
y: 0,
},
},
{
title: "圆形盒子",
componentName: "dragCircle",
id: "",
config: {
w: 150,
h: 150,
x: 0,
y: 0,
},
},
],
currentMove:{},
drawList:[]
}
}
methods:{
//点击左侧拖动克隆当前盒子,记录当前盒子的属性,也可直接记录index
cloneComponent(e) {
this.currentMove = {
id: "box_" + new Date().getTime(),
...e,
};
},
//拖动盒子到右边画布结束
handleEnd(e) {
const { newIndex } = e;
//这里的drawList是右边画布的list
this.drawList.push({
...this.currentMove
})
},
}
右边画布: 主要注意点就是,group设置成和左边名字一样的,然后对应组件的展示用动态组件进行展示。
<draggable
group="componentDrag"
animation="400"
v-model="drawList">
<component v-for="com in drawList" :key="com.id" :is="com.componentName"/>
</draggable>
这样即可实现左边元素克隆到右边画布效果,下一步我们就要实现画布缩放效果。
画布移动缩放
-
vue-drag-resize 常用属性介绍
这里使用的版本是^1.5.4,如果是以前的版本可能有点变化,具体参考 vue-drag-resize
isDraggable:true /false 是否可拖动。
isResizable:true /false 是否可缩放。
snapToGrid:true /false 是否设置每次移动距离。
w:盒子宽度。
h:盒子高度。
x:盒子left位置。
y:盒子top位置。
z:zIndex层级。
stickSize:缩放图标的大小。
activated:Function类型,单击组件时,组件活跃后触发。
deactivated:Function类型,单击组件外部,组件停止获取触发。
resizing:Function类型,缩放时触发。
resizestop:Function类型,缩放结束后触发。
dagging:Function类型,拖动时触发。
dragstop:Function类型,拖动结束后触发。
-
安装插件
npm install -s vue-drag-resize
-
引入插件(推荐局部引入)
import vueDragResize from "vue-drag-resize";
components: { vueDragResize}
-
组件中使用
画布位置:
<draggable
group="componentDrag"
animation="400"
v-model="drawList"
ghostClass="ghost">
<div
v-for="(com, index) in drawList"
:key="index"
:style="{ width: com.config.w + 'px', height: com.config.h + 'px' }"
>
<vue-drag-resize
:x="parseFloat(com.config.x)"
:y="parseFloat(com.config.y)"
:w="parseFloat(com.config.w)"
:h="parseFloat(com.config.h)"
@resizestop="handleResizeStop($event, com)"
@dragstop="handleDragStop($event, com)"
>
<component :is="com.componentName" />
</vue-drag-resize>
</div>
</draggable>
methods:{
//拖动盒子自适应
handleResizeStop(e, val) {
val.w = e.width;
val.h = e.height;
},
//拖拽移动停止
handleDragStop(e, val) {
val.x = e.left;
val.t= e.top;
},
}
实战演练
根据上面总结的,写了一个可视化拖拽的项目,有兴趣可以看看,源码在下方:
最后
到这里,通过插件实现已经完成了,后续会写一个原生实现拖拽和缩放的功能,敬请期待; 希望该文章能对你有帮助,如果疑问和建议,可在评论区留言,如果觉得本文写的不错,麻烦点个赞。
在线预览地址:vue-visual-drag
项目地址:vue-visual-drag