这几个做项目遇到一个上千节点的树结构,在考虑性能的前提下,直接用element的树组件会使系统页面卡顿现象,之后查询解决办法,偶遇ztree,这是一个树插件,在一次加载大量数据时有较好的性能表现,原理是,对于不展开的节点不进行渲染。官方解释如下:
感觉最近可能会用到它,所以学习了一下使用方法,并集成到vue中,并且自己做了一个小的例子,效果如下:
image.png
下面开始记录学习过程
首先将ztree放到vue项目中,需要先到官网下载压缩包并解压,官网地址:http://www.treejs.cn/v3/main.php#_zTreeInfo
然后复制css和js文件夹到vue项目中,如下图,我放到了plugins文件夹下,因为在这个例子中,加入了搜索功能,所以
jquery.ztree.excheck.min.js
和jquery.ztree.exhide.min.js
是必不可少的,对了,还必须引入jquery,因为jquery在别的文件夹就不展示了image.png
然后在main.js中进行引入,如下图:
image.png
案例源码:
<template>
<div class="ztree-box">
<el-row :gutter="20">
<el-col :span="4">
<div id="areaTree">
<el-input
id="key"
@keyup.enter.native="search"
v-model="keywords"
clearable
@clear="freshArea"
placeholder="请输入摄像头名称"
/>
<br />
<div class="tree-box">
<div class="zTreeDemoBackground left">
<ul id="treeDemo" class="ztree"></ul>
</div>
</div>
</div>
</el-col>
<el-col :span="20">
<div class="monitor-video">
<monitor-video ref="monitorVideo"></monitor-video>
</div>
</el-col>
</el-row>
</div>
</template>
<script>
import { list } from "@/api/element/monitor";
import MonitorVideo from "./monitor-video";
let that;
export default {
name: "zTree",
components: {
MonitorVideo,
},
data: function () {
return {
keywords: "",
hiddenNodes: [],
setting: {
view: {
// 关闭双击功能,以免与单击功能冲突
dblClickExpand: false,
addDiyDom: (treeId, treeNode) => {
that.addDiyDom(treeId, treeNode);
},
},
data: {
key: {
name: "label",
},
},
callback: {
onClick: (event, treeId, treeNode) => {
// 单击展开树
that.ztreeObj.expandNode(treeNode);
that.handleNodeClick(event, treeId, treeNode);
},
},
},
zNodes: [],
};
},
mounted() {
that = this;
// 获取树结构数据
this.zNodes = list.data;
this.zNodes[0].icon = "/static/lou.png";
// 初始化树
$.fn.zTree.init($("#treeDemo"), this.setting, this.zNodes);
// 获取树对象
this.ztreeObj = $.fn.zTree.getZTreeObj("treeDemo");
// 初始化树节点
this.initTree(this.ztreeObj.getNodes());
// 给重置按钮绑定事件
this.refreshEvent();
},
methods: {
initTree(datas) {
for (const item of datas) {
if (item.children.length > 0) {
item["isParent"] = true;
item["icon"] = "/static/lou.png";
this.initTree(item.children);
} else {
item["isParent"] = false;
item["icon"] = "/static/shexiangtou.png";
}
}
},
handleNodeClick(event, treeId, treeNode) {
if (!treeNode.isParent) {
this.$refs.monitorVideo.init();
}
},
// 添加自定义控件
addDiyDom(treeId, treeNode) {
if (treeNode.id === "0") {
var aObj = $("#" + treeNode.tId + "_a");
var editStr = `<i id="treeRefresh" class="el-icon-refresh tree-refresh"></i>`;
aObj.append(editStr);
}
},
// 重置按钮事件
refreshEvent() {
setTimeout(() => {
$("#treeRefresh").on("click", (e) => {
// 刷新树
that.freshArea();
that.$message.success("树已重置");
// 阻止事件冒泡
e.stopPropagation();
});
}, 300);
},
// 刷新树
freshArea() {
$.fn.zTree.init($("#treeDemo"), this.setting, this.zNodes);
this.initTree(this.ztreeObj.getNodes());
this.refreshEvent();
},
search() {
if (this.keywords) {
// 搜索树
this.searchZtree(this.ztreeObj, this.keywords);
this.$message.success("搜索完成");
}
},
searchZtree(ztreeObj, ztreeInput) {
//显示上次搜索后隐藏的结点
ztreeObj.showNodes(this.hiddenNodes);
function filterFunc(node) {
var keyword = ztreeInput;
//如果当前结点,或者其父结点可以找到,或者当前结点的子结点可以找到,则该结点不隐藏
if (
that.searchParent(keyword, node) ||
that.searchChildren(keyword, node.children)
) {
return false;
}
return true;
}
//获取不符合条件的叶子结点
this.hiddenNodes = ztreeObj.getNodesByFilter(filterFunc);
//隐藏不符合条件的叶子结点
ztreeObj.hideNodes(this.hiddenNodes);
},
searchChildren(keyword, children) {
if (children == null || children.length == 0) {
return false;
}
for (var i = 0; i < children.length; i++) {
var node = children[i];
if (node.label.indexOf(keyword) != -1) {
return true;
}
//递归查找子结点
var result = this.searchChildren(keyword, node.children);
if (result) {
return true;
}
}
return false;
},
searchParent(keyword, node) {
if (node == null) {
return false;
}
if (node.label.indexOf(keyword) != -1) {
return true;
}
//递归查找父结点
return this.searchParent(keyword, node.getParentNode());
},
},
};
</script>
<style>
@import "../../../../plugins/ztree/css/metroStyle/metroStyle.css";
.tree-refresh {
position: relative;
z-index: 999;
left: 10px;
font-size: 14px;
}
#areaTree {
padding: 20px 10px 20px 10px;
border: 1px solid #e5e5e5;
margin-bottom: 2px;
border-radius: 4px;
overflow: auto;
width: 100%;
height: 850px;
}
.box-title {
width: 30%;
overflow: auto;
border-radius: 3px 3px 0 0;
background-color: #f5f5f5;
}
.box-title .fa {
float: right;
line-height: 20px;
}
</style>
monitor-video文件
<template>
<div class="video-tag-box">
<div class="video-container">
<video width="800" height="450" id="videoTag" autoplay controls loop>
<source :src="src" />
</video>
</div>
</div>
</template>
<script>
export default {
data() {
return {
src: null,
videoTag: null,
};
},
mounted() {
this.videoTag = document.getElementById("videoTag");
},
methods: {
init() {
this.src = "/static/video/" + Math.ceil(Math.random() * 15) + ".mp4";
console.log(this.src);
this.videoTag.load();
},
},
};
</script>
<style>
.video-tag-box {
width: 100%;
height: 850px;
padding-top: 250px;
box-sizing: border-box;
}
.video-container {
width: 800px;
height: 450px;
margin: auto auto;
border: 2px #000 solid;
border-radius: 8px;
overflow: hidden;
}
</style>
网友评论