用elemet-ui组件实现弹窗里的树形结构和拖拽功能
这个弹窗功能,主要是导出字段的设置,左边是树形字段结构,右边是选中的设置字段,字段可以拖动调顺序。我实现这个功能主要用的element-ui里的tree和dialog组件,及vuedraggable组件,如果没有拖拽功能差不多半个小时就搞定这个功能,就因为实现这个拖拽功能,浪费了很多时间,从昨天晚上八点多开始,一直折腾到十一点多,大致效果如图刚开始没考虑到拖拽会引起这么多问题,只是用store,.
这个弹窗功能,主要是导出字段的设置,左边是树形字段结构,右边是选中的设置字段,字段可以拖动调顺序。我实现这个功能主要用的element-ui里的tree和dialog组件,及vuedraggable组件,如果没有拖拽功能差不多半个小时就搞定这个功能,就因为实现这个拖拽功能,浪费了很多时间,从昨天晚上八点多开始,一直折腾到十一点多,大致效果如图
刚开始没考虑到拖拽会引起这么多问题,只是用store,state选中的字段,和选中的id给存起来,这样可以实现公用,及后面的设置存储数据
模拟数据如下
data2: [{
id: 1,
label: '一级 1',
children: [{
id: 4,
label: '二级 1-1',
children: [{
id: 9,
label: '三级 1-1-1'
}, {
id: 10,
label: '三级 1-1-2'
}]
}]
}, {
id: 2,
label: '一级 2',
children: [{
id: 5,
label: '二级 2-1'
}, {
id: 6,
label: '二级 2-2'
}]
}, {
id: 3,
label: '一级 3',
children: [{
id: 7,
label: '二级 3-1'
}, {
id: 8,
label: '二级 3-2'
}]
}]
import Service from './service'
import config from './config'
const store = {
namespaced: true,
state: {
checkedFields: [], //选中对象
fieldKeys: [], //选中的id
deepData: []
},
mutations: {
setCheckedFields (state, data = []) {
state.checkedFields = data
},
setFieldKeys (state, keys = []) {
state.fieldKeys = keys
},
setDeepData (state, data = []) {
state.deepData = data
}
}
}
export default store
后来发现在这个行不通,数据都是共用的,拖动,删除的实话容易造成排序问题,
后来就把选中的给深拷贝来一份,左右数据相当独立,在state中添加了一个变量,
deepData: []
mutations: {
setCheckedFields (state, data = []) {
state.checkedFields = data
},
setFieldKeys (state, keys = []) {
state.fieldKeys = keys
},
setDeepData (state, data = []) {
state.deepData = data
}
}
利用getters处理数据获取深拷贝后的id数据,如下
getters: {
deepKeys (state) {
const { deepData } = state
let arr = []
deepData.map(ele => {
arr.push(ele.id)
})
return arr
}
}
然后监听tree里面的复选框事件,再递归循环数据,对比是选中还是重置,然后再根据情况,修改deepData里的值,刚开始用的tree里的check-change事件,发现这个事件容易触发几次事件,如果在父节点上点击,这样就获取了重复数据,右边的数据也出现了重复现象,后来用check事件避免了这个问题
实现代码如下
//监听事件方法
handleCheckChange (data, checked) {
let isReset = checked.checkedKeys.every(ele => ele !== data.id)
if (!isReset) {
this.$refs.tree.store.nodesMap[data.id].expanded = true
data.unfold = true
this.dataCheck(data, !isReset)
} else {
this.dataCheck(data, !isReset)
}
this.setCheckedFields(this.$refs.tree.getCheckedNodes(true))
this.setFieldKeys(this.$refs.tree.getCheckedKeys(true))
},
dataCheck (obj, b) {
let arr = []
this.dataLoop(obj, arr)
if (b) {
this.setDeepData(cloneDeep(this.deepData.concat(arr)))
} else {
arr.forEach(ele => {
this.deepData.forEach(val => {
if (ele.id === val.id) {
this.deepData.splice(this.deepData.indexOf(val), 1)
this.setDeepData(cloneDeep(this.deepData))
}
})
})
}
},
//递归
dataLoop (obj, arr) {
let arr2 = obj.children
if (arr2) {
arr2.forEach(ele => {
this.dataLoop(ele, arr)
})
} else {
arr.push(obj)
}
}
删除功能是利用watch监听deepKeys变化,然后再设置
删除功能代码:
delItem (index) {
this.deepData.splice(index, 1)
}
watch监听deepKeys变化
watch: {
deepKeys (newkeys) {
if (newkeys) {
this.$refs.tree.setCheckedKeys(newkeys, true)
}
}
},
拖拽功能实现主要用的vuedraggable组件,实现代码如下:
<draggable
:list="child"
@end="dragEndHandle"
>
<li
v-for="(item, index) in child"
:key="item.id"
:index1="item.index"
>
<span>{{ item.label }}</span>
<div class="set-field-tool">
<i
class="icon iconfont icon-move"
/>
<i
class="icon iconfont icon-minus"
@click="delItem(index)"
/>
</div>
</li>
</draggable>
拖拽js代码如下:
dragEndHandle ({ oldIndex, newIndex }) {
const { deepData } = this
const item = deepData[oldIndex]
deepData.splice(oldIndex, 1)
deepData.splice(newIndex, 0, item)
}
更多推荐
所有评论(0)