<script setup lang="ts"> import { reactive, onMounted } from 'vue'; import { cloneDeep, isEmpty } from 'src/common/utils'; import nestedDraggable from './infra/nested.vue'; const data = [ { name: 'task 1', show: true, tasks: [ { name: 'task 2', show: true, tasks: [], }, ], key: '1', }, { name: 'task 3', show: true, tasks: [ { name: 'task 4', show: true, tasks: [], }, ], key: '2', }, { name: 'task 5', show: true, tasks: [], key: '3', }, ]; const state = reactive({ list: [] as any[], originalData: [] as any[], }); onMounted(() => { state.originalData = cloneDeep(data); handleData(data); state.list = data; }); function handleData(data: any, key = 'tasks', before = 0) { let index = 0; data.map((item: any) => { let indexstr; if (before) { indexstr = before + '-' + String(index); } else { indexstr = String(index); } item['test_index'] = indexstr; index++; if (!isEmpty(item[key])) { handleData(item[key], key, item['test_index']); } else { item[key] = []; } }); } function viewData() { console.log('查看 >>>>', state.list); } function onReset() { const data = cloneDeep(state.originalData); handleData(data); state.list = data; } // 拖拽结束 function dragEnd() { handleData(state.list); console.log('拖拽结束2', state.list); } function onAdd() { let obj: any = { name: null, tasks: [], key: Date.now(), }; state.list.push(obj); handleData(state.list); } // 删除 function delItem(data: any) { console.log('删除', data); data['test_delete'] = true; let res = handelDel(state.list); handleData(res); state.list = res; } function handelDel(listdata: any[]) { const chiledKey = 'tasks'; let newArr = [] as any[]; listdata.map((item) => { if (!isEmpty(item[chiledKey])) { item[chiledKey] = handelDel(item[chiledKey]); } if (!item['test_delete']) { newArr.push(item); } }); return newArr; } // 同级添加 function addItem(data: any) { console.log('同级添加', data); const key = 'tasks'; const indexList = data['test_index'].split('-'); let re: any; for (let i = 0; i < indexList.length; i++) { const item = indexList[i]; if (i === 0) { re = getTarget(state.list, Number(item)); } else { re = getTarget(re.target[key], Number(item)); } } let obj: any = { name: null, show: true, key: Date.now(), }; obj[key] = []; re.parent.push(obj); handleData(state.list); } // 子级添加 function addNest(data: any) { const key = 'tasks'; console.log('子级添加', data); const indexList = data['test_index'].split('-'); let re: any; for (let i = 0; i < indexList.length; i++) { const item = indexList[i]; if (i === 0) { re = getTarget(state.list, Number(item)); } else { re = getTarget(re.target[key], Number(item)); } } let obj: any = { name: null, show: true, key: Date.now(), }; obj[key] = []; re.target[key].push(obj); handleData(state.list); } function getTarget(list: any, index: number) { const target = list[index]; const parent = list; return { target, parent }; } function getParamData() { // let data = cloneDeep(state.list); let res = delTestKey(data); console.log('原来的格式', res); } function delTestKey(listdata: any[], delKey = 'test_index') { const chiledKey = 'tasks'; return listdata.map((item: any) => { if (!isEmpty(item[chiledKey])) { item[chiledKey] = delTestKey(item[chiledKey], delKey); } delete item[delKey]; return item; }); } </script> <template> <div class="box"> <div class="actions"> <q-btn color="primary" label="查看" @click="viewData" /> <q-btn color="primary" label="原来的格式" @click="getParamData" /> <q-btn color="primary" label="重置" @click="onReset" /> <q-btn color="primary" label="添加" @click="onAdd" /> </div> <div class="tree-box"> <nested-draggable :tasks="state.list" @onEnd="dragEnd" @addItem="addItem" @addNest="addNest" @delItem="delItem" /> </div> </div> </template> <style lang="scss" scoped> .actions { padding: 10px; display: flex; flex-direction: row; justify-content: flex-start; align-items: center; column-gap: 10px; } .tree-box { // width: 600px; height: 500px; box-sizing: border-box; // border: 1px solid brown; overflow: auto; > :nth-child(1) { // padding-right: 10px; } } </style>