vue使用vue2-org-tree-节点增删改查(已实现)
需要使用到树形图绘制人物关系节点,综合考虑选择了这个,结合elementUI实现。
需要使用到树形图绘制人物关系节点,综合考虑选择了这个,结合elementUI实现。
1.下载插件
npm i vue2-org-tree //树形图插件
npm install --save-dev less less-loader //less
注意点:
在main.js中引用vue2-org-tree后,若不显示效果,问题是没有引入相应的css,我的引入是import "vue2-org-tree/dist/style.css";
2.使用
<vue2-org-tree ref="tree" :key="treeDataKey" :data="treeData[0]" :horizontal="!horizontal" :collapsable="collapsable" :render-content="renderContent" @on-expand="onExpand" @on-node-click="NodeClick" :label-class-name="labelClassName" />
注意点
形成树形图的关键方法:
1.renderContent ——初始渲染树形图
renderContent (h, data) {
return (
<div>
<el-popover placement="top-start" trigger="hover">
<el-button size="mini" class="addBtn" icon="el-icon-circle-plus-outline"
onClick={() => { this.openAddFrom(data) }}
>
添加节点
</el-button>
<div slot="reference">
<div class="treeItem">
<div class="controlIcon">
<i class={classType(data.type)}></i>
</div>
<span class="item_name">
{data.name}
</span>
</div>
</div>
</el-popover>
</div >
)
},
这里是我结合elementUI,并且对样式做出了一下改变的样子,
原始样子是:
renderContent (h, data) {
return (
<div>
<div slot="reference">
<div class="treeItem">
<span class="item_name">
{data.name}
</span>
</div>
</div>
</div >
)
},
2.节点中的子节点展开控制
1.collapse —— 控制当前节点的子节点是否展开
2.onExpand —— 关闭当前节点展开函数,并且关闭其下所有子节点的展开
3.toggleExpand ——控制所有节点是否展开,两个参数分别指的是期望展开的数据,是否展开(true:false)
collapse (list) {
list.forEach((child) => {
if (child.expand) {
child.expand = false;
}
child.children && this.collapse(child.children);
});
},
onExpand (e, data) {
if ("expand" in data) {
data.expand = !data.expand;
this.changeRender()
if (data.expand && data.children) {
this.collapse(data.children);
}
} else {
this.$set(data, "expand", true);
}
},
toggleExpand (data, val) {
if (Array.isArray(data)) {
data.forEach((item) => {
this.$set(item, "expand", val);
if (item.children) {
this.toggleExpand(item.children, val);
}
});
} else {
this.$set(data, "expand", val);
if (data.children) {
this.toggleExpand(data.children, val);
}
}
},
我这里使用的开关控制全部展开和关闭
效果:
1.展开全部
2.关闭"张一_姐姐"的展开:
应该有人发现了,自带的这个开关,字数长度不确定的情况下,竖排展示是对不齐的,解决办法是固定宽度,但是我直接没用了,后期用再加上吧。
ps:总体开关控制展开按钮
按钮:
<el-switch v-model="expandAll" active-text="展开全部" inactive-text="关闭全部" @change="expandChange">
</el-switch>
方法:
expandChange () {
this.toggleExpand(this.treeData[0], this.expandAll)
},
功能总览:
1.展示形式切换(横排/竖排)这里默认竖排
2.新增节点、删除节点、修改节点、查询节点
3.新建分支、选中分支
4.上传本地文本快速渲染分支
1.展示形式切换(横排/竖排)这里默认竖排
a.设置按钮
<el-switch v-model="horizontal" :disabled="!treeData.length" active-text="竖排" inactive-text="横排">
</el-switch>
b.绑定值
vue2-org-tree中 :horizontal="!horizontal"
效果:
竖排:
横排:
2.节点操作
2-1新增节点
逻辑:鼠标置上时候显示新增的按钮,点击后弹出输入框,可输入新增节点数据,点击保存即可在当时节点下新增节点
a:渲染时候给每个节点添加这个按钮和相应方法
renderContent (h, data) {
return (
<div>
<el-popover placement="top-start" trigger="hover">
<el-button size="mini" class="addBtn" icon="el-icon-circle-plus-outline"
onClick={() => { this.openAddFrom(data) }}
>
添加节点
</el-button>
<div slot="reference">
<div class="treeItem">
<div class="controlIcon">
<i class={classType(data.type)}></i>
</div>
<span class="item_name">
{data.name}
</span>
</div>
</div>
</el-popover>
</div >
)
},
点击添加后,可选择关系
添加后
添加节点时,首先获取当前节点的值,然后在其子集下添加新增的节点数据即可,但是要注意的是每个节点的id必须具有唯一性,不然会有很多问题:
核心代码:
点击添加节点时,获取当前节点
openAddFrom (data) {
this.spouseArr = [];
this.pitchSpouse = {
pitchSpouseId: ''
};
this.dialogFormVisible = true;
this.nowAddNode = data;
this.addId = data.id; //这个是主要的,当前节点id
},
根据id,获取当前节点的下标、所有父级、类型
findNodeInTree (data, id, type, callback) {
this.currentNodeMsg.type = type; //类型
for (let i = 0; i < data.length; i++) {
if (data[i].id == id) {
return callback(data[i], i, data)
}
if (data[i].children) {
let hasId = data[i].children.find((item) => {
if (item.id == id) {
this.currentNodeMsg.fatherArr = data[i]; //所有父级
}
})
this.findNodeInTree(data[i].children, id, type, callback)
}
}
},
//调用
this.findNodeInTree(this.treeData, this.addId, 'add', (item, index, arr) => {
this.currentNodeMsg.idx = index;//下标
})
新增节点时,我是调用自己写的方法,这里简化出来
// 判断是否是根节点 -- 旧版
if (this.currentNodeMsg.fatherArr.hasOwnProperty("name")) {
this.currentNodeMsg.fatherArr.children[this.currentNodeMsg.idx].children.push(this.addForm)
} else {
data[0].children.push(this.addForm)
}
-----------------------------
data—— this.treeData;节点树数据
this.addForm—— 当前新增的节点数据
这是简易版新增,只需要判断是否是对根节点进行添加即可,我修改后的是根据关系进行不同方式的添加,这里一般无需这么繁琐。
主要的核心问题在于变化后,你怎样去渲染节点树
解决办法:给vue2-org-tree添加绑定key值,更新数据后直接调用方法刷新key即可:
:key="treeDataKey"
// 重新渲染关系树
changeRender () {
this.treeDataKey += 1;
},
还有一个问题是,我这是本地数据,只有数据地址一致的时候,修改后才能对原数据进行直接修改,不然会繁琐很多
最麻烦的添加数据写完了,核心代码就是findNodeInTree
这个方法,接下来节点的修改,删除就大家自己发挥。
2.2查询节点
// 搜索事件
searchBtn () {
//判断当前是否显示关系树
if (this.treeData.length) {
this.findName(this.treeData, this.searchNodeName);
return
}
this.$message.warning("当前未显示分支图");
},
// 查找当前输入节点名称
findName (data, name) {
data.forEach((item, index) => {
if (item.name == name) {
this.searchNodeTree = []
this.searchNodeTree.push(item)
this.treeData = this.searchNodeTree;
return
}
this.findName(item.children, name)
})
},
3.新建分支、选中分支
1.新建分支
// 新建节点树
addNodeTree () {
this.loading = true;
// 判断当前分支是否存在
let state = this.branchNameRepeat(this.branchMsg.label)
if (state) {
this.$message.warning("分支名不能重复")
this.loading = false;
return
}
this.branchMsg.value = randomId();
// 赋予默认根节点
this.branchMsg.data.push(
{
id: randomId(),
name: '始先祖',
sex: "1",
type: "father",
children: []
}
)
this.centerDialogVisible = false;
this.nodeTree.push(this.branchMsg)
this.nodeTreeValue = this.branchMsg.value
this.$message.success("新建成功!");
this.loading = false;
this.resetFormBtn();
},
--------- watch中 -----------
"nodeTreeValue": {
handler (n, o) {
//根据id获取当前分支
if (n) {
[this.treeData, this.beforeTreeData] = [this.nodeTree.find((item) => {
return item.value == n
}).data, this.nodeTree.find((item) => {
return item.value == n
}).data]
}
},
deep: true
},
// 判断节点名称是否重复
branchNameRepeat (name) {
let isRepeat = this.nodeTree.find((item) => {
return item.label == name;
})
return isRepeat ? true : false
},
//随机Id
const randomId = function () {
return (Math.random() + new Date().getTime()).toString(32).slice(0, 8);
};
添加分支的逻辑:
1.nodeTree中以数组形式存放所有的分支总数,
2.根据添加的名称判断已有分支中是否重名,
3.符合条件后,设置初始数据,添加到nodeTree中,
4.拿到当前最新添加的树的id,
5.动态监听添加的关系树的id,发生变化时进行匹配,拿到相应的值,并且进行渲染,
nodeTree数据结构:
选择分支就是下拉形式获取 nodeTreeValue,nodeTreeValue改变时继续被监听,然后渲染对应的数据。
<el-select v-model="nodeTreeValue" placeholder="请选择分支">
<el-option v-for="item in nodeTree" :key="item.value" :label="item.label" :value="item.value">
</el-option>
</el-select>
4.上传本地文本快速渲染分支
上传按钮:
<el-upload class="upload-demo" action="" ref="upload" :on-change="handlePreview" :auto-upload="false" multiple :limit="1"
:file-list="fileList">
<el-button class="
el-icon-upload2" size="small" type="primary">点击上传</el-button>
<div slot="tip" class="el-upload__tip">只能上传txt文件</div>
</el-upload>
上传文件代码
// 上传文件
handlePreview (file) {
let that = this;
this.$refs.upload.clearFiles();
let fileName = file.name.split(".");
// 读取文件名称
if (fileName[1] != "txt") {
this.$message.error("只能上传txt文件");
return
}
// 文件名称-分支名称
let branchName = fileName[0];
let state = this.branchNameRepeat(branchName)
if (state) {
this.$message.warning("分支名不能重复")
return
}
let reader = new FileReader(); //先new 一个读文件的对象 FileReader
if (typeof FileReader === "undefined") { //用来判断你的浏览器是否支持 FileReader
this.$message({
type: "info",
message: "您的浏览器不支持文件读取。"
});
return;
}
reader.readAsArrayBuffer(file.raw); //读任意文件
reader.onload = function (e) {
var ints = new Uint8Array(e.target.result); //要使用读取的内容,所以将读取内容转化成Uint8Array
// ints = ints.slice(0, 5000); //截取一段读取的内容
let snippets = new TextDecoder('gb2312').decode(ints); //二进制缓存区内容转化成中文(即也就是读取到的内容)
// 判断是否能过解析为数组
try {
let nowSniData = JSON.parse(snippets)
that.branchMsg.value = randomId();
that.branchMsg.label = branchName;
// 赋予默认根节点
that.branchMsg.data = nowSniData;
that.nodeTree.push(that.branchMsg)
that.nodeTreeValue = that.branchMsg.value
that.$message.success("上传成功");
that.resetFormBtn()
} catch {
that.$message.error("转换失败,请注意内容是否为JSON格式");
}
};
},
上传逻辑:
1.txt中编辑好数据,点击按钮进行上传,
2.使用try catch判断txt文件内容是否符合数据格式,
3.符合条件后获取文本名称,判断名称是否与已存在的分支名重复,
4.符合条件后将赋予id,设置当前分支名称为文本名称,
5.追加到节点树数组中,渲染最新添加的数据
演示:
文本:
选中文本
渲染
更多推荐
所有评论(0)