前言:
此功能的来源来自于当时需要制作一个便于客户操作的打印设计功能,然后就有了这个项目。这个帖子主要是用于分享与谈论,相互学习。
目标:
- 能在vue页面中拖拽组件
- 支持批量操作拖动
- 通过拖拽组件列表里的组件到page进行添加
- 实现多种组件,如文本,图片,表格,网格等
- 便于扩展组件
- 页面中的单位统一,实现所见即所得
- 等等
当全部功能整理完毕后,会把此demo开源
目前效果:
设计
预览
实现:
组件在页面中的显示与拖拽移动位置
显示主要是使用了在page这个div上相对定位(position: relative;),里面的组件使用绝对定位(position: absolute;)使用top和left来绑定x坐标与y坐标即可。
这里使用了vue中的component标签来v-for动态生成组件,这个具体的后面会说明
<component
:is="moduleData.type"
:com="moduleData"
:class="[moduleData.isSelect && moduleData.config.isChildren? 'active':'']"
:data-title="moduleData.type"
:key="moduleData.uuid"
:val="moduleData"
class="layer"
></component>
拖拽移动主要使用了@mousedown获取点击的元素是否是组件,(这个我就是通过在组件html原始上绑定data-xxx属性来判断的)如果是组件就给组件元素或者在页面上绑定一个mousemove事件(这里选择的是在页面上绑定),当鼠标mouseup时移除事件即可
关键代码:
handleMouseDown(e){
// 如果没有选中组件 在画布上点击时需要调用 e.preventDefault() 防止触发 drop 事件
if(recursionGetSelectCom(this.$vptd.state.page.tempItems).length===0)
e.preventDefault()
var target = this.selectTarget(e.target)
//判断是不是选中了组件,如果是组件不向下执行
if (target) {
e.stopPropagation()
e.preventDefault()
var uuid = target.getAttribute('data-uuid')
// 设置选中元素
this.$vptd.commit('select', {
uuid: uuid,
})
// 绑定移动事件:除背景图以外的元件才能移动
let element = recursionGetSelectCom(this.$vptd.state.page.tempItems).filter(i=>i.uuid===uuid)
if (element.length > 0 && element[0].config.dragable) {
//绑定选中com事件
this.initmovement(e,element[0]) // 参见 mixins
return
}
}
this.hideArea()
// 获取编辑器的位移信息,每次点击时都需要获取一次。主要是为了方便开发时调试用。
const rectInfo = this.$refs.edit.getBoundingClientRect()
this.editorX = rectInfo.x
this.editorY = rectInfo.y
const startX = e.clientX
const startY = e.clientY
this.start.x = startX - this.editorX
this.start.y = startY - this.editorY
// 展示选中区域
this.isShowArea = true
const move = (moveEvent) => {
this.width = Math.abs(moveEvent.clientX - startX)
this.height = Math.abs(moveEvent.clientY - startY)
if (moveEvent.clientX < startX) {
this.start.x = moveEvent.clientX - this.editorX
}
if (moveEvent.clientY < startY) {
this.start.y = moveEvent.clientY - this.editorY
}
}
const up = (e) => {
document.removeEventListener('mousemove', move)
document.removeEventListener('mouseup', up)
if (e.clientX === startX && e.clientY === startY) {
console.log("鼠标未移动,取消选中")
this.$vptd.commit('setSelectElement', [])
}else {
//获取选中的组件然后给选中组件中的isSelect值进行改变
console.log("鼠标框选")
this.$vptd.commit('setSelectElement', this.getSelectArea())
}
this.hideArea()
}
document.addEventListener('mousemove', move)
document.addEventListener('mouseup', up)
},
通过拖拽组件列表里的组件到page进行添加
其中主要是用了@dragstart与@drop与@dragover方法
组件列表:html
<div class="item"
:key="index"
:draggable="true"
@dragstart="dragStart($event, index)"
@click="(e) => {addTempItem(e,item)}">
<span :style="{fontWeight:item.config.isEdit? 'bold':'',fontStyle:item.config.isEdit? '':'italic'}">{{ item.title }}</span>
</div>
组件列表:js
methods: {
// 添加组件
addTempItem (e, item) {
this.$vptd.dispatch('addTempItem', item)
},
dragStart (ev, index) {
ev.dataTransfer.setData('index', index)
}
},
设计页面html
<div
:style="{
height: '100px',
width: '100px',
}"
ref="edit"
class="screen"
@dragover.prevent="dragOver"
@drop="dropToAddCom($event)"
@mousedown="handleMouseDown"
>
</div>
设计页面js
dragOver(ev){
ev.preventDefault()
},
dropToAddCom(ev){
ev.preventDefault()
const rest = this.$refs.edit.getBoundingClientRect();
this.$vptd.dispatch('addTempItemByIndex',
{ index : ev.dataTransfer.getData('index'),
x: Math.round(ev.clientX-rest.x),
y :Math.round(ev.clientY-rest.y)
})
},
以上就是组件拖拽添加与在page上的拖拽设计,以上代码都不可直接使用,因为代码不全,仅仅能提供参考,或者自行修改也可
后续的更新等我忙完这段时间了补上。。。