目前项目中需要实现一个可拖拽的穿梭框并且是要多选,看了网上很多资料只有单选拖拽, 自己动手丰衣足食吧!
首先在element组件库提供的穿梭框组件的基础上去增加拖拽功能
这里我们要用到一个第三方拖拽组件sortablejs
安装sortablejs
npm i sortablejs --save-dev
html代码
<div class="transferBox">
<el-transfer
ref="transfer"
v-model="inputForm.workingProcedure"
:titles="['未选择工序', '已选择工序']"
target-order="push"
:props="transferProps"
:data="transferData"
@left-check-change="leftCheckChange"
@right-check-change="rightCheckChange"
>
<span slot-scope="{ option }"
draggable="!option.disabled"
@dragstart="drag($event, option)"
>
{{ option.workingProcedureName }}
</span>
</el-transfer>
</div>
js代码
data 数据
import Sortable from 'sortablejs'
export default {
data() {
return {
transferData: [], // 穿梭框数据
transferLeftCheckData: [], // 左侧选中数据
transferRightCheckData: [], // 右侧选中数据
draggingKey: '', // 当前拖拽项
inputForm:{
workingProcedure: [],
},
transferProps: { // 配置项可根据数据源配置所选字段
key: 'workingProcedureId', // 穿梭框内容的值
label: 'workingProcedureName' // 穿梭框所显示的字段
}
}
},
mounted生命周期
在mounted里执行, 防止会获取不到ref报错
如果有特殊的触发方式可写在函数内
弹窗最好包裹在this.$nextTick内触发
mounted() {
const transfer = this.$refs.transfer.$el
const leftPanel = transfer.getElementsByClassName('el-transfer-panel')[0].getElementsByClassName('el-transfer-panel__body')[0]
const rightPanel = transfer.getElementsByClassName('el-transfer-panel')[1].getElementsByClassName('el-transfer-panel__body')[0]
const rightEl = rightPanel.getElementsByClassName('el-transfer-panel__list')[0]
Sortable.create(rightEl, {
onEnd: evt => {
const { oldIndex, newIndex } = evt
const temp = this.inputForm.workingProcedure[oldIndex]
if (!temp || temp === 'undefined') {
return
} // 解决右边最后一项从右边拖左边,有undefined的问题
this.$set(this.inputForm.workingProcedure, oldIndex, this.inputForm.workingProcedure[newIndex])
this.$set(this.inputForm.workingProcedure, newIndex, temp)
}
})
const leftEl = leftPanel.getElementsByClassName('el-transfer-panel__list')[0]
Sortable.create(leftEl, {
onEnd: evt => {
const { oldIndex, newIndex } = evt
const temp = this.transferData[oldIndex]
if (!temp || temp === 'undefined') {
return
} // 解决右边最后一项从左边拖右边,有undefined的问题
this.$set(this.transferData, oldIndex, this.transferData[newIndex])
this.$set(this.transferData, newIndex, temp)
}
})
leftPanel.ondragover = ev => {
ev.preventDefault()
}
leftPanel.ondrop = ev => {
ev.preventDefault()
// 往左拉
const index = this.inputForm.workingProcedure.indexOf(this.draggingKey)
if (index !== -1) {
// 如果当前拉取的是选中数据就将所有选中的数据拉到左边选中框内
if (this.transferRightCheckData.indexOf(this.draggingKey) !== -1) {
// 此处为多选执行
this.transferRightCheckData.reduce((arr, item) => {
if (arr.indexOf(item) !== -1) {
// 每次计算将相同的删掉
arr.splice(arr.indexOf(item), 1)
}
return arr
}, this.inputForm.workingProcedure)
this.transferRightCheckData = []// 清除右侧选中的 不然下次向左拉取时会有缓存
// 否则就只拉取当前一个
} else {
this.inputForm.workingProcedure.splice(index, 1)
}
}
}
rightPanel.ondragover = ev => {
ev.preventDefault()
}
rightPanel.ondrop = ev => {
ev.preventDefault()
// 右边框里没有当前key值的时候 向右拉
if (this.inputForm.workingProcedure.indexOf(this.draggingKey) === -1) {
// 此处为多选执行
// 如果当前拉取的是选中数据就将所有选中的数据拉到右边选中框内
if (this.transferLeftCheckData.indexOf(this.draggingKey) !== -1) {
this.inputForm.workingProcedure =
this.inputForm.workingProcedure.concat(this.transferLeftCheckData)
this.transferLeftCheckData = [] // 清除左侧选中的 不然下次向右拉取时会有缓存
} else {
// 否则就只拉取当前一个
this.inputForm.workingProcedure.push(this.draggingKey)
}
}
}
},
methods方法
methods: {
drag(ev, option) {
// 赋值当前拖拽的唯一标识
this.draggingKey = option.workingProcedureId
},
leftCheckChange(val) {
// 穿梭框左侧多选选中
this.transferLeftCheckData = [...val]
},
rightCheckChange(val) {
// 穿梭框右侧多选选中
this.transferRightCheckData = [...val]
}
}
目前写出的效果勉强够用,但是多选拉取时的重影还未实现, 有想法的可以留言一块改进!1CE4B8DA.jpg
1CE6375C.jpg