使用vuedraggable 对一个 二维列表
实现拖拽修改
vuedraggable实现座位布局拖拽修改
方案一
修改 end
,和move
,在move
中获取移动的元素值,和目的地元素值,在end
中交换这两个元素
局限
- 元素需要是唯一值,不能有重复的
因为每次只能获取到值,而不是元素的位置,这就导致需要遍历整个列表查询位置,很麻烦 - 在创建删除队列后,无法将元素拖到删除队列
实现
<vue-draggable
:disabled="!draggable"
v-model="arrange[row-1]"
group="arrange"
:move="dragMoveHandler"
@end="dragEndHandler"
>
<div class="seat-arrange-col" slot="header" style="user-select: none;">
<div class="col-index">
{{ row }}
</div>
</div>
<div class="seat-arrange-col" v-for="col in arrange[row - 1].length" :key="'col' + col">
<seat-block :key="'row' + row + 'col'+ col" :is-select="selectStatus[row-1][col-1]"
:type="arrange[row-1][col-1]"
:row="row - 1"
:col="col - 1"
@seat-select="selectBlockHandler"
:isDrag="draggable"
/>
</div>
<div class="seat-arrange-col" slot="footer">
<div class="col-bt">
<el-button v-if="draggable" icon="el-icon-plus" type="primary"
circle
size="mini"
:disabled="!canAdd(arrange[row-1])"
@click="addSeatHandler(row-1)"
>
</el-button>
</div>
</div>
</vue-draggable>
dragMoveHandler(evt, originalEvent) {
this.moveStart = { element: evt.draggedContext.element, index: evt.draggedContext.index }
this.moveEnd = { element: evt.relatedContext.element, index: evt.relatedContext.index }
return false
},
dragEndHandler(evt) {
let relatedRow = -1, draggedRow = -1
for (let i = 0; i < this.arrange.length; i++) {
if (draggedRow !== -1 && relatedRow !== -1) break
if (draggedRow === -1 && this.arrange[i][this.moveStart.index] === this.moveStart.element) {
draggedRow = i
}
if (relatedRow === -1 && this.arrange[i][this.moveEnd.index] === this.moveEnd.element) {
relatedRow = i
}
}
this.$set(this.arrange[draggedRow], this.moveStart.index, this.moveEnd.element)
this.$set(this.arrange[relatedRow], this.moveEnd.index, this.moveStart.element)
},
效果(为了导出的gif比较小,就去色了)
![演示一](https://img-blog.csdnimg.cn/294892e2997f46e4ad676eb59f27569c.gif#pic_center)
方案二
突然发现 可以在 vue-draggable
标签里添加自定义标签,可以从move的to
和from
里面的$attrs
拿到,这就好办了,以前那种方法就是因为不知道怎么获取移动开始元素和目的地元素的信息,才只能用全局搜索的方法定位,现在的话可以直接获取就好办多了
![在这里插入图片描述](https://img-blog.csdnimg.cn/1649bd786cbd4e64a4547fa71da1a2c3.png#pic_center)
实现(代码写得很乱,能用就行,哈哈哈哈)
思路就是在vue-draggable
加属性用来标记属于哪个分组以及是哪一行,我用的divide
表示分组,row
表示是二维数组的哪一行
vue那里就是覆写move和end,move里面记录每次移动的参数,最后一次的参数就是目的地,end里面就是判断从那里移动到哪里,并执行移动
移动需要用this.$set
或者是其他能出发更新的,比如数组的pop
,push
等方法,这里用的splice(arr,index,remove,...addItem)
,第一个参数的数组,第二个是操作位置,第三个是在这个位置往后要移除多少元素,后面的参数是移除后插入的元素
<vue-draggable
:disabled="!draggable"
v-model="arrange[row-1]"
group="arrange"
:row="row-1"
divide="arrange"
:move="dragMoveHandler"
@end="dragEndHandler($event,'arrange')"
>
<div class="seat-arrange-col" slot="header" style="user-select: none;">
<div class="col-index">
{{ row }}
</div>
</div>
<div class="seat-arrange-col" v-for="col in arrange[row - 1].length" :key="'col' + col">
<seat-block :key="'row' + row + 'col'+ col" :is-select="selectStatus[row-1][col-1]"
:type="arrange[row-1][col-1]"
:row="row - 1"
:col="col - 1"
@seat-select="selectBlockHandler"
:isDrag="draggable"
/>
</div>
<div class="seat-arrange-col" slot="footer">
<div class="col-bt">
<el-button v-if="draggable" icon="el-icon-plus" type="primary"
circle
size="mini"
:disabled="!canAdd(arrange[row-1])"
@click="addSeatHandler(row-1)"
>
</el-button>
</div>
</div>
</vue-draggable>
dragMoveHandler(evt, originalEvent) {
let from = evt.from.__vue__.$attrs
let to = evt.to.__vue__.$attrs
if(from == null || to == null) return;
this.moveFrom = { row: from.row, index: evt.draggedContext.index, divide: from.divide }
this.moveTo = { row: to.row, index: evt.relatedContext.index, divide: to.divide }
return false
},
dragEndHandler(evt) {
if (this.moveTo.divide === 'arrange' && this.moveTo.index == null) return
if (this.moveFrom.divide === this.moveTo.divide === 'deleted') return
let elementTo = this.getElement(this.moveTo.divide, this.moveTo.row, this.moveTo.index)
let elementFrom = this.getElement(this.moveFrom.divide, this.moveFrom.row, this.moveFrom.index)
if (this.moveFrom.divide === 'deleted' && this.moveTo.divide === 'arrange') {
if (elementTo > 0) {
this.$set(this.arrangeDeleted, this.moveFrom.index, elementTo)
} else {
this.arrangeDeleted.splice(this.moveFrom.index, 1)
}
this.$set(this.arrange[this.moveTo.row], this.moveTo.index, elementFrom)
}
if (this.moveFrom.divide === 'arrange' && this.moveTo.divide === 'arrange') {
this.$set(this.arrange[this.moveFrom.row], this.moveFrom.index, elementTo)
this.$set(this.arrange[this.moveTo.row], this.moveTo.index, elementFrom)
}
if (this.moveFrom.divide === 'arrange' && this.moveTo.divide === 'deleted') {
this.arrangeDeleted.push(elementFrom)
this.$set(this.arrange[this.moveFrom.row], this.moveFrom.index, -1)
}
},
getElement(divide, row, index) {
if (divide === 'deleted') {
return this.arrangeDeleted[index]
} else if (divide === 'arrange') {
return this.arrange[row][index]
}
return undefined
},
效果(完美,只需要处理下删除列,让它自动换行)
![演示二](https://img-blog.csdnimg.cn/b078b18b28f64742a940b07b1352a46d.gif#pic_center)
缺陷
因为是交换元素,所以在移动到删除列的时候需要有个格子在那才能拖过去
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)