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

在移动端实现一个类似于element ui的el-tree的树形控件,要实现当前高亮的叶子节点的父节点都要展开

场景:用树形控件展示数据结构为树状的带有目录的文章标题,用uni-app插件市场的ly-tree实现,
地址:https://ext.dcloud.net.cn/plugin?id=1000

【注】:该组件存在问题,没办法用组件自带的方法defaultExpandedKeys实现父节点自动展开,于是另外写了一个方法getAbsolutePathByNodeKey去获取当前节点的所有父节点,或者可以采用组件自带的getNodePath方法获取当前节点的所有父节点

<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/ly-tree.vue";
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 = arr.length; i < len; i++) {
        //             let node = arr[i];

        //             stack.push(node.id);
        //             if (node.id === key) {
        //                 return stack;
        //             } else if (node.children && node.children.length > 0) {
        //                 let temp = find(key, node.children);

        //                 if (temp[temp.length - 1] === key) return temp;
        //                 else temp.pop();

        //                 if (i + 1 < len) continue;

        //                 return temp;
        //             } else {
        //                 stack.pop();

        //                 if (i + 1 < len) continue;

        //                 return stack;
        //             }
        //         }
        //     }

        //     return find(key, vm.treeData);
        // },
        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;
                    // vm.defaultExpandedKeys = vm.getAbsolutePathByNodeKey(
                    //     vm.currentNodeKey
                    // );
                }
            });
        },
        //过滤节点的方法
        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>
  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值