最近公司开发中遇到对element-ui中el-tree增删改操作, 从后台返回拿到的数据操作之后,发现本地无法进行改变, 注意!!! 拿到数据之后通过lodash插件进行深拷贝之后,操作本地data数据, 在将本地data数据格式化之后传输给后台.
组件代码
<template>
<div class="lalala tree-container">
<el-tree
:data="treeData"
node-key="id"
default-expand-all
@node-click="handleLeftclick"
@node-drag-start="handleDragStart"
@node-drag-enter="handleDragEnter"
@node-drag-leave="handleDragLeave"
@node-drag-over="handleDragOver"
@node-drag-end="handleDragEnd"
@node-drop="handleDrop"
@node-contextmenu="rightClick"
draggable
:allow-drop="allowDrop"
:allow-drag="allowDrag"
ref="tree"
>
<span class="slot-t-node" slot-scope="{ node, data }">
<span v-show="!data.isEdit">
<span :class="[data.id >= 99 ? 'slot-t-node--label' : '']">{{
node.label
}}</span>
</span>
<span v-show="data.isEdit">
<el-input
class="slot-t-input"
size="mini"
autofocus
v-model="data.label"
:ref="'slotTreeInput' + data.id"
@blur.stop="NodeBlur(node, data)"
@keydown.native.enter="NodeBlur(node, data)"
></el-input>
</span>
</span>
</el-tree>
<el-card
class="box-card"
ref="card"
v-show="menuVisible && dialogStatus != 'details'"
>
<div class="add" @click="addChildNode()" v-if="onlyShow">
<i class="el-icon-circle-plus-outline"></i> 添加章节
</div>
<div @click="addSameLevelNode()" v-show="firstLevel">
<i class="el-icon-circle-plus-outline"></i> 同级增加
</div>
<div class="add" @click="addChildNode()" v-if="firstLevel">
<i class="el-icon-circle-plus-outline"></i> 子级增加
</div>
<div class="upload" @click="uploadVideo" v-if="twoLevel">
<i class="el-icon-upload2"></i> 上传课程
</div>
<div class="delete" @click="deleteNode()" v-if="firstLevel || twoLevel">
<i class="el-icon-remove-outline"></i> 删除节点
</div>
<div class="edit" @click="editNode()" v-if="firstLevel">
<i class="el-icon-edit"></i> 修改节点
</div>
</el-card
</div>
</template>
<script>
import _ from "lodash";
import { uploadFile } from "@/api/corres";
export default {
props: {
chapters: {
type: Array,
default: [],
},
dialogStatus: {
type: String,
},
},
watch: {
chapters() {
this.initTreeData();
},
treeData: {
handler() {
console.log(this.treeData);
this.$emit("getTreeData", this.treeData[0].children);
},
deep: true,
},
},
name: "tree",
data() {
return {
rulesTree: {
lessonName: [
{ required: true, message: "请输入课程名称", trigger: "blur" },
],
lessonTime: [
{ required: true, message: "请输入课程时长", trigger: "blur" },
],
lessonUrl: [{ required: true, message: "请上传视频", trigger: "blur" }],
},
entity: {
lessonName: "",
lessonTime: "",
},
dialogFormVisibleTree: false,
onlyShow: false,
eleId: "",
isShow: false,
currentData: "",
currentNode: "",
menuVisible: false,
firstLevel: false,
twoLevel: false,
maxexpandId: 4,
treeData: [
{
id: 0,
label: "课程目录",
children: [],
},
],
defaultProps: {
children: "children",
label: "label",
},
};
},
methods: {
initTreeData() {
let chapters = _.cloneDeep(this.chapters);
chapters.forEach((item) => {
item.label = item.chapterName;
item.firstLevel = true;
item.isEdit = false;
item.lessons.forEach((i) => {
i.label = i.lessonName;
i.twoLevel = false;
i.fileName = i.lessonName;
i.lessonTime = +i.lessonTime.slice(0, i.lessonTime.indexOf("分钟"));
});
item.children = item.lessons;
});
this.$set(this.treeData[0], "children", chapters);
},
forceUpdate() {
this.$forceUpdate();
},
// 上传视频
async uploadLessonTree(file, type) {
const qq = new FormData();
qq.append("file", file.file);
qq.append("type", 1);
const res = await uploadFile(qq);
console.log(res, "上传");
// this.entity.url = res.fileUrl;
this.$set(this.entity, "lessonUrl", res.fileUrl);
this.$set(this.entity, "fileName", res.fileName);
console.log(this.entity);
},
// 上传视频之前校验类型
beforeUploadTree(file) {
let FileExt = file.name.replace(/.+\./, "");
let flag = ["mp4"].includes(FileExt);
if (!flag) this.$message.error("文件格式错误请重新上传!");
return flag;
},
// dialog 确定
sureClickTree() {
this.$refs.ruleForm.validate((valid) => {
if (valid) {
this.entity.isEdit = false;
this.$set(this.currentData, "label", this.entity.lessonName);
this.$set(this.currentData, "lessonUrl", this.entity.lessonUrl);
this.$set(this.currentData, "lessonTime", this.entity.lessonTime);
this.$set(this.currentData, "fileName", this.entity.lessonName);
this.treeData[0].children.forEach((item) => {
item.children.forEach((i) => {
if (i.label == this.currentData.label) {
i.lessonName = this.currentData.label;
i.lessonUrl = this.currentData.lessonUrl;
i.lessonTime = this.currentData.lessonTime;
i.fileName = this.currentData.fileName;
i.label = this.currentData.label;
}
});
});
console.log(this.treeData);
this.dialogFormVisibleTree = false;
}
});
},
// 关闭dialog
handleCloseTree() {
this.dialogFormVisibleTree = false;
this.entity = this.$options.data().entity;
},
NodeBlur(Node, data) {
console.log(Node, data);
if (data.label.length === 0) {
this.$message.error("菜单名不可为空!");
return false;
} else {
if (data.isEdit) {
this.$set(data, "isEdit", false);
console.log(data.isEdit);
}
this.$nextTick(() => {
this.$refs["slotTreeInput" + data.id].$refs.input.focus();
});
}
},
allowDrop(draggingNode, dropNode, type) {
console.log(draggingNode, dropNode);
if (
(draggingNode.level == 2 && dropNode.level == 1) ||
(draggingNode.level == 2 && dropNode.level == 3) ||
(draggingNode.level == 1 && dropNode.level == 2) ||
(draggingNode.level == 3 && dropNode.level == 2) ||
(draggingNode.level == 3 && dropNode.level == 4) ||
(draggingNode.level == 3 && dropNode.level == 1)
) {
return false;
} else {
return type === "prev" || type === "next";
}
},
allowDrag(draggingNode) {
return draggingNode.data.label.indexOf("三级 3-2-2") === -1;
},
// 鼠标右击事件
rightClick(event, object, Node, element) {
this.currentData = object;
this.currentNode = Node;
if (Node.level === 1) {
this.onlyShow = true;
} else {
this.onlyShow = false;
}
if (Node.level === 2) {
this.firstLevel = true;
} else {
this.firstLevel = false;
}
if (Node.level == 3) {
this.twoLevel = true;
} else {
this.twoLevel = false;
}
this.menuVisible = true;
// let menu = document.querySelector('#card')
// /* 菜单定位基于鼠标点击位置 */
// menu.style.left = event.clientX + 'px'
// menu.style.top = event.clientY + 'px'
document.addEventListener("click", this.foo);
this.$refs.card.$el.style.left = event.clientX - 80 + "px";
console.log(event.clientY + 400);
this.$refs.card.$el.style.top = event.clientY - 600 + "px";
},
// 鼠标左击事件
handleLeftclick(data, node) {
this.foo();
},
// 取消鼠标监听事件 菜单栏
foo() {
this.menuVisible = false;
// 要及时关掉监听,不关掉的是一个坑,不信你试试,虽然前台显示的时候没有啥毛病,加一个alert你就知道了
document.removeEventListener("click", this.foo);
},
// 增加同级节点事件
addSameLevelNode() {
let id = Math.ceil(Math.random() * 100);
var data = { id: id, label: "新增节点" };
this.$refs.tree.append(data, this.currentNode.parent);
},
// 增加子级节点事件
addChildNode() {
console.log(this.currentData);
console.log(this.currentNode);
if (this.currentNode.level >= 3) {
this.$message.error("最多只支持三级!");
return false;
}
let id = Math.ceil(Math.random() * 100);
var data = { id: id, label: "新增节点", children: [] };
this.$refs.tree.append(data, this.currentNode);
},
// 删除节点
deleteNode() {
this.$refs.tree.remove(this.currentNode);
},
// 编辑节点
editNode(data) {
this.currentData = data ? data : this.currentData;
if (!this.currentData.isEdit) {
this.$set(this.currentData, "isEdit", true);
}
// 获取焦点
this.$nextTick(() => {
this.$refs["slotTreeInput" + this.currentData.id].focus();
});
},
handleDragStart(node, ev) {
// console.log("drag start", node);
},
handleDragEnter(draggingNode, dropNode, ev) {
// console.log("tree drag enter: ", dropNode.label);
},
handleDragLeave(draggingNode, dropNode, ev) {
// console.log("tree drag leave: ", dropNode.label);
},
handleDragOver(draggingNode, dropNode, ev) {
// console.log("tree drag over: ", dropNode);
},
handleDragEnd(draggingNode, dropNode, dropType, ev) {
// console.log("tree drag end: ", dropNode && dropNode.label, dropType);
},
handleDrop(draggingNode, dropNode, dropType, ev) {
// console.log("tree drop: ", dropNode.label, dropType);
},
},
};
</script>
<style lang="scss" scope>
</style>
注意从页面拿到数据, 通过watch属性监听页面传入的数据, 否则页面和组件的mounted拿数据会起冲突.