Element-UI 自定义Tree组件
背景
根据业务修改element tree 组件,实现增删改节点时不收起节点不需要重新渲染整个树组件
源码
<template>
<div>
<el-tree
:props="props"
:load="loadNode"
:data="setTree"
@node-click="clickFn"
lazy
ref="tree"
>
<span class="custom-tree-node" slot-scope="{ node, data }">
<span class="label">{{ node.label }}</span>
<span>
<template v-for="(item, index) in methodName">
<template v-if="data.unIcon">
<i
:class="'el-icon-' + item"
@click.stop="() => update(node, data, item)"
style="margin-right: 10px"
:key="index"
v-if="!data.unIcon.includes(item)"
></i>
</template>
<template v-else>
<i
:class="'el-icon-' + item"
@click.stop="() => update(node, data, item)"
style="margin-right: 10px"
:key="index"
></i>
</template>
</template>
</span>
</span>
</el-tree>
</div>
</template>
<script>
import Element from "element-ui";
export default {
props: {
getTreeData: [Function],
addFn: [Function],
editFn: [Function],
method: [Array, Object]
},
computed: {
methodName() {
let arr = [];
for (let k in this.method) {
arr.push(k);
}
return arr;
}
},
data() {
return {
setTree:[],
oneTree: [],
props: {
label: "name",
isLeaf: "leaf"
},
currentModel: false
};
},
methods: {
clickFn(data,node,dom) {
this.$emit("getNode", {node: node, type: 'click'})
},
async loadNode(node, resolve) {
//判断一级 二级
let data =
node.level === 0
? {}
: {
type: node.level,
id: node.data.id
};
let list = await this.getTreeData(data);
if(node.level === 0) {
this.oneTree = list;
}
return resolve(list);
},
async update(node, data, type) {
this.$emit("getNode", {node: node, type: type})
this.currentModel = true;
let type_title = ""; // 弹窗标题
let type_text = ""; // 弹窗内容
let defaultData = {};
switch (type) {
case "add":
type_title = "新增";
//填充默认值
defaultData = {
inputPlaceholder: `请输入${data.title}`
};
break;
case "edit":
type_title = "编辑";
//填充默认值
defaultData = {
inputPlaceholder: `请输入${data.title}`,
inputValue: data.name
};
break;
case "delete":
type_title = "删除";
//填充默认值
type_text = `确定要删除${data.name}${data.title}?`;
break;
}
const MessageBoxType = type == "delete" ? "$confirm" : "$prompt"; // 判断弹窗类型
this[MessageBoxType](
type_text,
`${type_title}${data.title}`,
defaultData
).then(async ({ value }) => {
// console.log('>>>>>>>', value)
let d = {
type: node == null ? 1 : node.level,
id: data.id,
name: value
};
// 新增
if (type == "add") {
if(node == null) {
delete d.type;
}
let res = await this.method.add(d);
let newChild = { id: res.id, name: value, children: [] };
if(res.unIcon) { //icon
newChild.unIcon = res.unIcon
}
if(res.leaf) { // 是否有子集
newChild.leaf = res.leaf
}
if(res.title) { // title
newChild.title = res.title
}
if (!data.children) {
this.$set(data, "children", []);
}
console.log('>>>>>>11111222', data)
if(node == null){
// console.log('>>>>>', node)
this.setTree = this.oneTree
this.setTree.push(newChild)
} else {
// console.log('>>>>>', node)
this.$refs['tree'].append(newChild,node);
}
return false;
}
// 编辑
if (type == "edit") {
await this.method.edit(d);
data.name = value;
return false;
}
// 删除
if (type == "delete") {
delete d.name;
await this.method.delete(d);
const parent = node.parent
this.$refs['tree'].remove(node);
}
});
}
}
};
</script>
<style scoped>
/deep/.custom-tree-node {
flex: 1;
display: flex;
align-items: center;
justify-content: space-between;
font-size: 14px;
padding-right: 8px;
}
/deep/.el-tree-node__content {
display: flex;
align-items: center;
height: 26px;
cursor: pointer;
margin: 8px 0;
}
/deep/.el-icon-add:before {
content: "\e783";
}
/deep/.el-icon-edit:before {
content: "\e764";
}
.label{
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
display: inline-block;
max-width: 145px;
}
</style>
使用方式
getNode方法为自定义组件返回的点击的node事件,用于判断当前点击的某个node,及事件类型:add,edit,del, click;
<xtAdminTree
@getNode="handleNodeClick" //返回点击的节点
:getTreeData="getTreeData" //获取数据进行渲染
:method="{
add: addSubjectFn, //新增方法
edit: editSubject, // 编辑方法
delete: deleteSubject, //删除方法
}"
ref="tree"
/>
渲染方法
getTreeData(data) {
return new Promise((resolve, reject) => {
console.log("获取层级数据", data);
this.openType = data.type ? data.type : 0;
console.log("this.openType", this.openType);
if (data.type && data.type > 0) {
data.campus_id = data.id;
delete data.id;
delete data.type;
}
console.log("获取列表参数", data);
campusList(data).then((res) => {
if (res.code == 1) {
this.listLoading = false;
let list = res.data;
list = res.data.map((item) => {
return {
id: item.id,
name: item.name,
leaf: this.openType == 1,
title: this.modelLabelList[this.openType].inputLabel,
unIcon: this.openType == 1 ? ["add"] : [],
};
});
resolve(list);
} else {
this.$message.error("获取校区数据异常");
resolve([]);
}
});
});
},
点击节点事件
//点击树节点的事件 , 点击事件如果不是click,需要动态传入模态框的title,用于弹框显示不同文字类型
handleNodeClick(data) {
console.log("node点击事件", data);
// console.log("checked", checked);
if (data.type == "click") {
if (data.node.level == 2) {
this.listQuery.page = 1;
this.isTableTitle = true;
this.tableTitle = data.node.data.name;
this.tableNode = Object.assign({}, data.node);
this.getTableByID(data.node);
}
} else if (data.type == "add") {
console.log('data.node',data.node)
if(data.node != null){
data.node.data.title = this.modelLabelList[data.node.level].inputLabel
}
} else if (data.type == "edit") {
data.node.data.title = this.modelLabelList[data.node.level-1].inputLabel
}
},
method方法为新增,编辑,删除的方法,返回一个promise
//新增
addSubjectFn(data) {
console.log("新增data", data);
this.openType = data.type ? data.type : 0;
return new Promise((resolve, reject) => {
if (!data.name || data.name == "") {
this.$message.error("提交名称不得为空,请输入后再次提交");
reject();
} else {
if (data.type && data.type == 1) {
data.campus_id = data.id;
}
delete data.type;
delete data.id;
addCampus(data).then((res) => {
// console.log("this.openType", this.openType);
if (res.code == 1) {
if (this.openType == 0) {
res.data.leaf = false;
res.data.title = "校区名称";
} else if (this.openType == 1) {
res.data.unIcon = ["add"];
res.data.leaf = true;
res.data.title = "分校区名称";
}
this.$message.success("新增操作成功");
resolve(res.data);
} else {
this.$message.error(res.msg);
reject(res.msg);
}
});
}
});
},
//编辑
editSubject(data) {
console.log("编辑data", data);
return new Promise((resolve, reject) => {
if (!data.name || data.name == "") {
this.$message.error("提交名称不得为空,请输入后再次提交");
reject();
} else {
editCampus(data).then((res) => {
if (res.code == 1) {
this.$message.success("编辑操作成功");
if (data.type == 2) {
this.initTable();
}
resolve();
} else {
this.$message.error(res.msg);
reject(res.msg);
}
});
}
});
},
//删除
deleteSubject(data) {
return new Promise((resolve, reject) => {
deleteCampus(data).then((res) => {
if (res.code == 1) {
this.$message.success("删除校区操作成功");
if (data.type == 2) {
this.initTable();
}
resolve();
} else {
this.$message.error("删除校区操作异常");
reject(res.msg);
}
});
});
},
本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!