这个弹窗功能,主要是导出字段的设置,左边是树形字段结构,右边是选中的设置字段,字段可以拖动调顺序。我实现这个功能主要用的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: [], //选中的iddeepData: []},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 } = statelet 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 = truedata.unfold = truethis.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.childrenif (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"><liv-for="(item, index) in child":key="item.id":index1="item.index"><span>{{ item.label }}</span><div class="set-field-tool"><iclass="icon iconfont icon-move"/><iclass="icon iconfont icon-minus"@click="delItem(index)"/></div></li></draggable>
拖拽js代码如下:
dragEndHandle ({ oldIndex, newIndex }) {const { deepData } = thisconst item = deepData[oldIndex]deepData.splice(oldIndex, 1)deepData.splice(newIndex, 0, item)}