美文网首页
小程序中的树形控件

小程序中的树形控件

作者: 肾仔博 | 来源:发表于2021-09-30 09:37 被阅读0次

    参考:https://segmentfault.com/a/1190000021286232
    工作了一段时间,很久没写关于代码上的学习记录,这是在公司处理一个树形控件时寻找解决方法时看到的一篇文章,很有效地帮助到我,非常感谢!!

    因为公司的原因,对代码进行了一些修改,但总体的操作理念比较符合我的需求。

    以下的代码都是关于微信小程序作为开发

    首先先新建一个放自定义组件的文件夹(components),组件的名称根据自己的开发来定义,我这边就称它为(tree)组件,下面为tree组件的全部代码
    (技巧:新建组件文件一般都是右键点击文件夹-然后选择 '新建Component'-这样就能快速新建一个组件文件)也不算啥技巧,估计大家都知道#125

    tree.wxml

    \triangleright 有些wx:if的判断可以暂时没用,因为公司代码用到,所以我就直接复制上去了(我比较懒),还有里面用到的图片(tick.png),只是一张打勾的图片,随便上网找下就是了

    <view>
        <block wx:for="{{tree}}" wx:key="index">
            <view style="display:flex;align-items:center;margin-left:{{item.nodes.length !== 0 ? depth*20 : depth*30}}px;font-size:36rpx;margin-top: 5px;"
                wx:if="{{item.category !== 'index'}}">
                <view class="tree_left" wx:if="{{item.nodes.length !== 0}}" data-id="{{item.id}}" data-open="{{item.open}}"
                    bindtap="onchange">
                    <view class="{{!item.open ? 'icon-right' : 'icon-down'}}"></view>
                </view>
    
                <view class="{{item.nodes.length !== 0 ?'parent':'node'}} " data-id="{{item.id}}" data-open="{{item.open}}"
                    bindtap="onchange">
                    {{item.name}}
                    <view class="selected" wx:if="{{item.category !== 'index'}}" catchtap="handleClick"
                        data-id="{{item.id}}" data-value="{{item.name}}">
                        <image hidden="{{item.selected === false}}" src="../../pages/image/tick.png"
                            style="width:20px;height:20px;"></image>
                    </view>
                </view>
            </view>
            <block wx:if="{{item.nodes}}">
                <view hidden="{{!item.open}}">
                    <tree treeList="{{item.nodes}}" id="treeSelect" bind:onclick="click" bind:change="change"
                        depth="{{depth+1}}"></tree>
                </view>
            </block>
        </block>
    </view>
    

    tree.wxss

    .tree_left{
        position: relative;
        float: left;
    }
    
    .icon-down{
        border: 8px solid;
        border-color: transparent transparent #B8B8B8;
        transform: rotate(180deg);
        margin-top: 7px;
        margin-left: 5px;
        margin-right: 10px;
    }
    
    .icon-right{
        border: 8px solid;
        border-color: transparent transparent #B8B8B8;
        transform: rotate(90deg);
        margin-left: 5px;
    }
    
    .selected{
        height: 20px;
        width: 20px;
        border-radius: 50%;
        border: 1px solid #D6D6D6;
        float: right;
        margin-left: 5px;
        margin-top: 2px;
    }
    

    tree.js

    const tranverse = (e) => {
        for (let i in e) {
            if (e[i].nodes) {
                e[i].open = false;
                tranverse(e[i].nodes)
            }
            e[i].selected = false;
        }
    }
    Component({
        properties: {
            treeList: Object,
            depth: {
                type: Number,
                value: 0
            }
        },
        data: {},
        ready() {
            // const {treeList}=this.properties; 
            const { treeList } = this.data;
            for (let i in treeList) {
                if (treeList[i].nodes) {
                    treeList[i].open = false;
                    tranverse(treeList[i].nodes);
                }
                treeList[i].selected = false;
            }
            this.setData({
                tree: treeList
            })
        },
        methods: {
            //修改折叠状态
            changeOpen(tree, id) {
                for (let i = 0; i < tree.length; i += 1) {
                    if (tree[i].id === id) {
                        tree[i].open = !tree[i].open;
                    }
                    if (tree[i].nodes.length !== 0) {
                        this.changeOpen(tree[i].nodes, id);
                    }
                }
                return;
            },
            onchange(e) {
                const { treeList } = this.data;
                const { id } = e.currentTarget.dataset;
                this.changeOpen(treeList, id);
                this.triggerEvent('change', id, { bubbles: true, composed: true });
                this.setData({
                    tree: treeList
                })
            },
            change(e) {
                const id = e.detail;
                const { treeList } = this.data;
                this.changeOpen(treeList, id);
                this.setData({
                    tree: treeList
                })
            },
            click(e) {
                const t = this.selectAllComponents('#treeSelect');
                t.forEach(item => {
                    item.click(e);
                })
                let id = '';
                if (e.detail) {
                    id = e.detail.id;
                }
                const { treeList } = this.data;
                this.setStatus(treeList, id);
                this.setData({
                    tree: treeList
                })
            },
            handleClick(e) {
                const t = this.selectAllComponents('#treeSelect');
                t.forEach(item => {
                    item.click(e);
                })
                //   const {id}=e.currentTarget.dataset;
                const { id, value } = e.currentTarget.dataset;
                const { treeList } = this.data;
                // const value = this.getData(treeList, id)
                this.setStatus(treeList, id);
                this.triggerEvent('onclick', { id, value, treeList }, { composed: true, bubbles: true });
                this.setData({
                    tree: treeList
                })
            },
            //切换选中状态
            setStatus(tree, id) {
                for (let i = 0; i < tree.length; i += 1) {
                    if (tree[i].id == id) {
                        tree[i].selected = true;
                    } else {
                        tree[i].selected = false;
                    }
                    if (tree[i].nodes) {
                        this.setStatus(tree[i].nodes, id);
                    }
                }
                return;
            },
            //获取选中项信息
            getData(tree, id) {
                for (let i = 0; i < tree.length; i += 1) {
                    if (tree[i].id === id) {
                        return tree[i].name;
                    }
                    if (tree[i].nodes) {
                        this.getData(tree[i].nodes, id);
                    }
                }
                return '';
            },
        }
    })
    

    tree.json

    {
        "component": true,
        "usingComponents": {
            "tree": "/components/tree/tree"
        }
    }
    

    当你写完这个tree组件的时候,是时候验证它的展示效果,
    注意:这里的数据是写死的,请根据自己开发需求进行代码上的修改

    随便新建一个Page页面,为demo页面

    demo.wxml

    \triangleright 这个treeList传的内容为一个数组对象,如:[{..},{...}],这样子的数据

    <tree treeList="{{treeList}}" id="treeSelect" bind:onclick="treeClick"></tree>
    

    demo.wxss

    /* 这里没写样式,可以自己设计 */
    

    demo.json

    \triangleright 这里路径一般根据自己的项目文件来引用,并不一定要按我的写法

    {
       "usingComponents": {
        "tree": "../../components/tree/tree"
      }
    }
    

    demo.js

    Page({
         data: {
            treeList: [
                {
                    id: '1',
                    pid: '0',
                    name: '祖先节点',
                    nodes:[
                        {
                            id: '1-1',
                            pid: '1',
                            name: '父节点1',
                            nodes:[
                                {
                                    id: '1-1-1',
                                    pid: '1-1',
                                    name: '子节点1',
                                    nodes: []
                                }
                            ]
                        },
                        {
                            id: '1-2',
                            pid: '1',
                            name: '父节点2',
                            nodes:[
                                {
                                    id: '1-1-2',
                                    pid: '1-1',
                                    name: '子节点2',
                                    nodes: []
                                }
                            ]
                        }
                    ]
                }
            ]
        },
    
        treeClick(e) {
            console.log(e)
            const t = this.selectAllComponents('#treeSelect');
            t.forEach(item => {
                item.click(e);
            })
            const { id, value } = e.detail;
            console.log(e.detail)
        }
    })
    

    展示效果如下:


    树形控件.gif

    总结:刚开始做公司的这个需求的时候,感觉难度应该不大,可惜我是程序员中的菜鸡,需要找资料才能解决掉,不懂就百度,这是个日常的操作。不说那么多废话,这个树形控件的使用请留意原文章作者的描述(描述的非常详细),因为之前用的树形控件都是不能够进行单选的操作,所以寻找了很多处理方法都搞不掂,最后找到了这边文章,并在原代码进行一定的修改,发现可以满足我的需求,这是非常不错的!!这里再次感谢写这篇文章的作者,因为真的帮到我了,哈哈哈,请原谅我是菜鸡。

    当然这个树型控件还是存在一些缺陷,假如节点越来越多又或者节点上的文字宽度占的比例较大的话,会显得比较丑陋,还是需要多加改进。

    相关文章

      网友评论

          本文标题:小程序中的树形控件

          本文链接:https://www.haomeiwen.com/subject/ptmjnltx.html