在移动端实现一个类似于element ui的el-tree的树形控件

时间:2025-01-18 17:35:13
<template> <view class=""> <movable-area class="moableArea" @tap="showNav"> <movable-view class="movableView" direction="vertical" x="600rpx" y="800rpx" > <view class="navigator-button"> <u-icon name="list-dot"></u-icon> 导航 </view> </movable-view> </movable-area> <u-popup v-model="showNavList" mode="bottom" border-radius="18"> <view class="nav-top"> <view class="nav-title">导航</view> <view class="learn-center-search"> <u-search v-model="filterText" :show-action="false" height="80" shape="square" bg-color="#FFF" placeholder-color="#999999" border-color="#D9D9D9" > </u-search> </view> </view> <scroll-view scroll-y style="width: 100%; height: 100%; padding-bottom: 20rpx" > <view class="nav-content"> <ly-tree ref="tree" :tree-data="manualList" :filter-node-method="filterNode" :ready="ready" node-key="id" @node-expand="handleNodeExpand" @node-click="handleNodeClick" :props="props" :check-on-click-node="true" :highlight-current="true" :current-node-key="id" :default-expanded-keys="defaultExpandedKeys" :accordion="true" > </ly-tree> </view> </scroll-view> </u-popup> </view> </template> <script> import LyTree from "@/components/ly-tree/"; export default { data() { return { showNavList: false, ready: false, //这里用于自主控制loading加载状态,避免异步正在加载数据的空挡显示“暂无数据” manualList: [], props: { label: "name", children: "children", }, filterText: "", defaultExpandedKeys: [], parentIdList: [], parentList: [], }; }, components: { LyTree, }, props: { id: { type: String, default: () => { return ""; }, }, }, mounted() { let vm = this; vm.$nextTick(() => { vm.getManualList(); }); }, watch: { filterText(val) { this.$refs.tree.filter(val); }, }, methods: { //可以通过这个算法去获取当前节点的所有父节点 // getAbsolutePathByNodeKey(key) { // let vm = this; // let stack = []; // function find(key, rest) { // for (let i = 0, arr = rest, len = ; i < len; i++) { // let node = arr[i]; // (); // if ( === key) { // return stack; // } else if ( && > 0) { // let temp = find(key, ); // if (temp[ - 1] === key) return temp; // else (); // if (i + 1 < len) continue; // return temp; // } else { // (); // if (i + 1 < len) continue; // return stack; // } // } // } // return find(key, ); // }, showNav() { let vm = this; vm.showNavList = true; vm.parentIdList = []; vm.$nextTick(() => { if (vm.id) { vm.$refs.tree.setCurrentKey(vm.id); //通过getNodePath方法找到当前节点的所有父节点,并把id都push到一个空数组里 vm.parentList = vm.$refs.tree.getNodePath(vm.id); for (let i = 0; i < vm.parentList.length; i++) { vm.parentIdList.push(vm.parentList[i].id); } vm.defaultExpandedKeys = vm.parentIdList; // = ( // // ); } }); }, //过滤节点的方法 filterNode(value, data) { if (!value) return true; return data.name.indexOf(value) !== -1; }, // uni-app中emit触发的方法只能接受一个参数,所以会回传一个对象,打印对象即可见到其中的内容 handleNodeClick(obj) { if (obj.data.type == "article") { let platformList = { 1: "圆方1.0", 2: "数据集市", 3: "Seele平台", 4: "圆方2.0", }; switch (obj.data.rootName) { case "最新动态": uni.navigateTo({ url: `/pages/learnCenter/components/detailPage?newsId=${ obj.data.id }&platform=${ platformList[obj.data.data.platform] }&module=${obj.data.rootName}`, }); break; case "使用手册": uni.navigateTo({ url: `/pages/learnCenter/components/detailPage?issueId=${ obj.data.id }&platform=${ platformList[obj.data.data.platform] }&module=${obj.data.rootName}`, }); break; case "教学社区": uni.navigateTo({ url: `/pages/learnCenter/components/detailPage?documentId=${ obj.data.id }&platform=${ platformList[obj.data.data.platform] }&module=${obj.data.rootName}`, }); break; case "视频教学": uni.navigateTo({ url: `/pages/learnCenter/components/videoDetail?videoId=${ obj.data.id }&platform=${ platformList[obj.data.data.platform] }&module=${obj.data.rootName}`, }); break; default: break; } } }, handleNodeExpand(obj) { console.log("handleNodeExpand", obj); }, //处理数据结构的方法 parse(root, newRoot) { let vm = this; let i; let len; let node; let newNode; len = root.length; for (i = 0; i < len; i++) { node = root[i]; newNode = {}; if ( node.issueId || node.newsId || node.documentId || node.videoId ) { if (node.issueId) { newNode.id = node.issueId; newNode.rootName = "使用手册"; } if (node.newsId) { newNode.id = node.newsId; newNode.rootName = "最新动态"; } if (node.documentId) { newNode.id = node.documentId; newNode.rootName = "教学社区"; } if (node.videoId) { newNode.id = node.videoId; newNode.rootName = "视频教学"; } newNode.name = node.title; newNode.status = node.status; newNode.type = "article"; newNode.isSelect = false; } else if (node.catalogueId) { newNode.id = node.catalogueId; newNode.name = node.catalogueName; newNode.type = "catalog"; newNode.children = []; newNode.catalogNode = true; newNode.topId = node.topId; if (node.catalogueResponseList) { vm.parse(node.catalogueResponseList, newNode.children); } if (node.objectList) { vm.parse(node.objectList, newNode.children); } } newNode.data = { ...node, }; newRoot.push(newNode); } }, //获取后台数据 getManualList() { let vm = this; return new Promise((resolve, reject) => { vm.$req .doRequest({ alias: "dcs-catalogue-getCatalogueTree", query: { id: "0", type: "2", }, }) .then((res) => { if (res.code == 0) { vm.tempList = res.data.filter( (item) => item.catalogueName != "优秀案例" ); vm.parse(vm.tempList, vm.manualList); vm.ready = true; } return resolve(); }); }); }, }, }; </script> <style lang="less" scoped> /deep/.ly-tree-node__content.is-current { background-color: inherit; color: #0a63f1; } /deep/.is-expanded { } .nav-top { background: #fbfbfb; border-bottom: 1px solid #e9e9e9; padding: 36rpx 0 34rpx; .nav-title { margin: 0 46rpx 26rpx; font-family: PingFangSC-Medium; font-size: 32rpx; color: #333333; letter-spacing: 0.02px; } .u-search { margin: 42rpx auto 0 !important; width: 90%; } } .nav-content { background: #fff; padding: 20rpx 46rpx 38rpx; max-height: 962rpx; /deep/.ly-tree { padding: 0 !important; } /deep/.ly-tree-node__label { font-size: 30rpx; } /deep/.ly-empty { margin-top: 48rpx; } } .navigator-button { background: #ffffff; border-radius: 39rpx 0 0 39rpx; border-radius: 39rpx 0 0 39rpx; box-shadow: -4rpx 0 10rpx 0 rgba(0, 0, 0, 0.2); font-size: 28rpx; color: #202020; padding-left: 16rpx; /deep/ .uicon-list-dot { top: 3.8rpx !important; margin-right: 1px; font-size: 36rpx !important; margin: 0 10rpx 0 10rpx; color: #000; } } .moableArea { position: fixed; top: 0; left: 50rpx; width: 100%; height: 100%; pointer-events: none; z-index: 99999; } .movableView { pointer-events: auto; width: 186rpx; height: 78rpx; line-height: 78rpx; } </style>