做全國行政區劃的展示,包含街道數據有十幾萬條,全部加載接口比較慢,所以採取了table的懶加載,在新增子節點,編輯刪除節點的過程中,官方文檔裏面並沒有相對應的方法,裏面遇到了很多坑,這裏記錄一下實現方法。
1.首先界面如圖所示,業務場景:表格外層有創建按鈕,創建的是第一層節點,表格上的添加是指添加子節點,編輯和刪除是針對當前節點,編輯時可以編輯父級區劃;
2.表格界面主要代碼
<el-table
ref="table"
:loading="loading"
row-key="id"
:default-expand-all="false"
:lazy="true"
:load="load"
:tree-props="treeProps">
<el-table-column
prop="name"
label="行政區劃名稱"
min-width="200">
</el-table-column>
<el-table-column
prop="code"
label="行政區劃代碼"
min-width="200">
</el-table-column>
<el-table-column
label="操作"
min-width="200">
<template slot-scope="scope">
<el-button type="text" size="mini" @click="edit(scope)">編輯</el-button>
<span v-if="!scope.row.childrenCount">
<el-divider direction="vertical"></el-divider>
<el-button type="text" size="mini" @click="deleteItem(scope)">刪除</el-button>
</span>
<el-divider direction="vertical"></el-divider>
<el-button type="text" size="mini" @click="create(scope)">新增</el-button>
</template>
</el-table-column>
</el-table>
// 新增編輯彈窗組件
<create-or-update-region-model
:currentRow="currentRow"
:id="dialogCreateOrEdit.id"
:parentId="dialogCreateOrEdit.parentId"
v-model="dialogCreateOrEdit.isShow"
:parentRegionName="dialogCreateOrEdit.parentRegionName"
@editSuccess='handleEditOnSave'
@addSuccess='handleAddOnSave'></create-or-update-region-model>
3.js主要邏輯,分爲新增,編輯和刪除;
3.1新增
先判斷是否加到最外層,加到最外層就直接push數據到this.refs.table.store.stats.data裏面去;
如果不是最外層,先找到父級節點,將新的數據加入到父級的子節點中,並更新父級節點的子節點數量,具體方法見代碼中的
addLazyTableItemToParent()方法
3.2編輯
先判斷是否改變父級節點,如果沒有,直接更新數據;
如果改變了父級節點,先刪除原始父級節點上的此節點,再去新的父級節點上添加此子節點;
此段邏輯主要在handleEditOnSave(),findNewParent()方法中
3.3刪除
如果時最外層節點,直接在this.refs.table.store.stats.data裏面splice此數據;
如果是內層節點,則刪除該節點,並更新父級節點的子節點數量;
此段邏輯主要見deleteLazyTableItem()方法
下面是主要的js代碼
<script>
export default {
name: 'RegionIndex',
data () {
return {
currentRow: null,
treeProps: {
children: 'children',
hasChildren: 'childrenCount'
},
dialogCreateOrEdit: {}
};
},
methods: {
getItems (id) {
return new Promise((resolve, reject) => {
//接口相關,根據自己的接口處理
this.api.getList({ parent: id }).then((result) => {
resolve(result);
}).finally(() => {
this.loading = false;
}).catch((e) => {
reject(e);
});
});
},
async load (tree, treeNode, resolve) {
try {
let result = await this.getItems(tree.id);
resolve(result);
}
catch (e) {
this.loading = false;
}
},
handleRowClick (row, event, column) {
this.currentRow = row;
},
//打開新增彈窗
create (scope) {
if (scope) {
this.dialogCreateOrEdit.parentId = scope.row ? scope.row.id : -1;
this.currentRow = scope.row;
}
else {
this.dialogCreateOrEdit.parentId = -1;
}
this.dialogCreateOrEdit.id = null;
this.dialogCreateOrEdit.isShow = true;
},
//打開編輯彈窗
edit (scope) {
this.editItem = scope.row;
this.currentRow = scope.row;
this.dialogCreateOrEdit.parentId = scope.row.parent;
this.dialogCreateOrEdit.id = scope.row.id;
this.dialogCreateOrEdit.isShow = true;
},
//刪除
deleteItem (scope) {
const item = scope.row;
this.$confirm(this.$t('app.common.message.deleteWarningMessage', { 0: '' })).then(async (result) => {
if (!result) {
return;
}
// 刪除接口,根據自己項目相應處理
await this.api.deleteItem({ id: item.id });
this.deleteLazyTableItem(item); this.$message.success(this.$t('app.common.message.successfullyDeleted'));
});
},
deleteLazyTableItem (item) {
const store = this.$refs.table.store;
if (item.parent != -1) {
let parentRow = store.states.data.find(child => child.id == item.parent);
if (!parentRow) {
const keys = Object.keys(store.states.lazyTreeNodeMap);
for (let i = 0; i < keys.length; i++) {
parentRow = store.states.lazyTreeNodeMap[keys[i]].find(child => child.id == item.parent);
if (parentRow) {
break;
}
}
}
parentRow.childrenCount--;
const parent = store.states.lazyTreeNodeMap[item.parent];
const index = parent.findIndex(child => child.id == item.id);
parent.splice(index, 1);
}
else {
const parent = store.states.data;
const index = parent.findIndex(child => child.id == item.id);
parent.splice(index, 1);
}
},
// 編輯行政區劃成功
handleEditOnSave (model) {
const newItemData = Object.assign({}, model);
const parentId = this.dialogCreateOrEdit.parentId;
if (model.parent == parentId) {
// 未編輯父級節點,更新當前數據
Object.assign(this.editItem, newItemData, {
childrenCount: this.editItem.childrenCount
});
}
else {
// 編輯父級節點,先刪除當前節點,再去新的父級節點添加子節點
this.deleteLazyTableItem(this.editItem);
if (model.parent == -1) {
// 添加最外層
this.addOuterTableItem(newItemData);
}
else {
this.findNewParent(model.parent, newItemData);
}
}
},
// 查找新的父節點及數據後,添加子節點
findNewParent (parentId, newItemData) {
const store = this.$refs.table.store;
// 首先在最外層裏面找
let parentRow = store.states.data.find(item => item.id === parentId);
if (parentRow) {
parentRow.childrenCount++;
}
// 不在最外層
else {
const keys = Object.keys(store.states.lazyTreeNodeMap);
for (let i = 0; i < keys.length; i++) {
parentRow = store.states.lazyTreeNodeMap[keys[i]].find(item => item.id == parentId);
if (parentRow) {
break;
}
}
if (parentRow) {
parentRow.childrenCount++;
}
}
const parentTreeNode = store.states.treeData[parentId];
this.addLazyTableItemToParent(parentTreeNode, parentId, newItemData);
},
// 新增行政區劃成功
handleAddOnSave (model) {
const newItemData = Object.assign({}, model);
const parentId = this.dialogCreateOrEdit.parentId;
const store = this.$refs.table.store;
if (parentId == -1) {
// 添加最外層
this.addOuterTableItem(newItemData);
}
else {
const parentRow = this.currentRow;
parentRow.childrenCount++;
// treeData爲所有已加載過的節點的子節點
const parentTreeNode = store.states.treeData[parentId];
this.addLazyTableItemToParent(parentTreeNode, parentId, newItemData);
}
},
// 添加數據放到最外層的數據中去
addOuterTableItem (newItemData) {
const store = this.$refs.table.store;
store.states.data.push(newItemData);
},
// 把數據加到父級節點上去
addLazyTableItemToParent (parentTreeNode, parentId, newItemData) {
const store = this.$refs.table.store;
// 如果在已加載過的節點的子節點中
if (parentTreeNode) {
// 如果該節點已加載
if (parentTreeNode.loaded) {
store.states.lazyTreeNodeMap[parentId].push(newItemData);
}
}
else {
store.states.treeData[parentId] = {
display: true,
loading: false,
loaded: false,
expanded: false,
children: [],
lazy: true,
level: 0
};
}
}
}
};
</script>