新项目需求:开发一个实时视频页面,左侧为视频播放部分,右侧为视频列表树,双击列表树的设备播放视频,并且判断播放状态回显到列表树上。后端没有接口可以反馈播放状态 (因为后端懒不愿写遍历的接口,如果可以后端遍历只需要改变树的数据就能动态刷新),所以只能用前端方法来实现列表树的播放状态
这时候就需要获取列表树的dom来进行递归遍历,因为是懒加载形成的树结构,所以需求获取整个dom结构来遍历改变样式
列表树html代码如下
<el-tree ref="tree" :data="treeData" node-key="id" :filter-node-method="filterNode" lazy :load="loadNode"
highlight-current :props="defaultProps" @node-click="handleNodeClick">
<div class="listItem" slot-scope="{ node, data }">
<!-- 树结构最后一层 -->
<div style="display: flex; align-items: center" v-if="node.level == 6">
<!-- 设备播放状态 -->
<div v-if="data.open" class="point" />
<div v-else class="noPoint" />
<!-- 设备在线状态 -->
<div :class="data.devStatus == 1 ? 'icon-on' : 'icon-1'" />
</div>
<!-- 判断是否是可播放的设备 -->
<span v-if="data.devCode" @dblclick="clkDb(data, node)" :title="data.name">{{ data.name }}</span>
<span v-else :title="data.name">{{ data.name }}</span>
</div>
</el-tree>
data里写el-tree的自定义叶子结点,用来判断是否可以点击展开下一层
defaultProps: {
children: "children",
label: "name",
isLeaf: "leaf",
},
页面布局如图
懒加载js代码如下
loadNode(node, reslove) {
this.chooseNode = node;
this.getTreeData(node, node.data.id, reslove);
},
async getTreeData(node, key, reslove) {
if (node.level === 0) {
this.treeLoading = true;
const { value } = await getPlatInfo({});
this.platInfo = value;
let treeArr = [{ name: this.platInfo.platName }];
reslove(treeArr);
this.treeLoading = false;
} else if (node.level === 1) {
const { value } = await getResourceInfo(this.platInfo.platCode);
let treeChildArr = value;
reslove(treeChildArr, "treeChildArr");
} else {
// 最后一级节点
if (node.data.resourceType == 4) {
getMeasurementPointInfo(node.data.id).then((res) => {
let arr = res.value;
// 初始化视频播放状态,默认为未播放状态
arr.forEach((item) => {
item.open = false;
});
reslove(arr);
});
} else {
getResourceInfo(node.data.id).then((res) => {
reslove(res.value);
});
}
}
},
这里区分了node.level是因为后端给的树第一层的接口和第二层不一样,可以根据项目情况自己灵活修改区分层级懒加载接口,最后呈现的数据都会reslove()方法回显出来
注意reslove()里需要加上之前自定义叶子节点的格式,如果没有leaf值需要自己判断加上
下面是动态遍历部分js代码
// 双击列表播放视频
clkDb(data, node) {
if (data.devStatus != 1) {
commonUtil.showTipInfo("选择的设备不在线,无法播放", "", "warning");
} else {
let result = this.videoPlay(
data.devCode,
);
result.then((resultVlaue) => {
this.removeRow(data);
});
}
},
removeRow(row, close) {
//递归el-tree节点
let allNodesDom = this.$refs.tree.root.childNodes;
function checkNodeDom(checkData) {
let currentIndex = null;
checkData.forEach((item, index) => {
//最后一层
if (item.childNodes.length == 0) {
//对比需要对比的参数
if (item.data.devCode == row.devCode) {
// 关闭视频时传入参数
if (close) {
item.data.open = false;
} else {
// 重置状态为未播放状态再判断播放结果
if (item.data.open == true) {
item.data.open = false;
}
if (item.data.devPtzIndex == row.devPtzIndex) {
currentIndex = index;
item.data.open = true;
}
}
}
} else if (item.childNodes.length > 0) {
checkNodeDom(item.childNodes);
}
});
return;
}
// 回调
checkNodeDom(allNodesDom);
},
这里通过递归遍历找到自己需要改变的节点数据,可以在遍历时调接口或者其他操作都可以,如果想改变节点数据可以判断节点level或者节点id再reslove()出来
在视频关闭的时候也需要调取removeRow()方法来遍历状态
总结:前端动态改变懒加载的树结构并不是很推荐,数据结构类尽量让后端来写比较好,有时候条件不允许也需要思考其他可以实现的办法进行开发。递归遍历部分的代码并没有精简优化,可以根据自己项目需求灵活修改。