返回顶部
首页 > 资讯 > 前端开发 > JavaScript >微信小程序实现多层级复选框菜单
  • 358
分享到

微信小程序实现多层级复选框菜单

2024-04-02 19:04:59 358人浏览 薄情痞子
摘要

目录一、背景二 、效果展示三、功能点四、代码实现五 、最后本文实例为大家分享了微信小程序自定义多层级复选框菜单的具体代码,供大家参考,具体内容如下 一、背景 因客户需要,有一个功能是

本文实例为大家分享了微信小程序自定义多层级复选框菜单的具体代码,供大家参考,具体内容如下

一、背景

因客户需要,有一个功能是需要注册用户时选择多个【单元 - 楼层 - 设备】的绑定,谷歌了一通,没有找到想要的,无奈之举只能手写一个…

二 、效果展示

三、功能点

1、初始化时,默认展开选中的菜单
2、点击每一层父级菜单,会自动折叠其子菜单
3、选中子级节点会默认选中父级节点
4、子级节点都没选中默认取消选中父级节点
5、选中父级节点默认选中其所有子级节点

四、代码实现

这里没写组件,如果需要可以改为组件。
可能会有一个疑问为哈是 treeMenu2 不是 treeMenu1
因为 treeMenu1 写的low,treeMenu2 升级了js代码。

1、treeMenu2.js

js里面的各种事件均为递归操作,可根据加载的数据动态进行操作。

// pages/biz/treeMenu/treeMenu.js
Page({

    
    data: {
        menuTreeImgLeft: "../../../icon/f_left.png",
        menuTreeImgBottom: "../../../icon/f_bottom.png",
        menuTree: [{
            "checked": false,
            "children": [{
                "checked": false,
                "children": [{
                    "id": "1-1-1",
                    "checked": true,
                    "field": "1",
                    "title": "设备1",
                }, {
                    "id": "1-1-2",
                    "checked": false,
                    "field": "2",
                    "title": "设备2"
                }],
                "id": "1-1",
                "field": "1-floor",
                "title": "1楼",
                "isHidden": true,
                "bindAll": false,
            }, {
                "checked": false,
                "children": [{
                    "checked": false,
                    "field": "3",
                    "title": "设备3"
                }],
                "id": "1-2",
                "field": "2-floor",
                "title": "2楼",
                "isHidden": true,
            }, {
                "checked": false,
                "children": [{
                    "id": "1-3-4",
                    "checked": true,
                    "field": "4",
                    "title": "设备4"
                }],
                "id": "1-3",
                "field": "3-floor",
                "title": "3楼",
                "isHidden": true,
            }],
            "id": "1",
            "isHidden": true,
            "bindAll": false,
            "field": "1-unit",
            "title": "1单元"
        }, {
            "checked": false,
            "children": [{
                "checked": false,
                "children": [{
                    "id": "2-1-1",
                    "checked": false,
                    "field": "5",
                    "title": "设备5"
                }],
                "id": "2-1",
                "field": "1-floor",
                "title": "1楼",
                "isHidden": true,
            }, {
                "checked": false,
                "children": [{
                    "id": "2-2-1",
                    "checked": false,
                    "field": "6",
                    "title": "设备6"
                }],
                "id": "2-2",
                "field": "2-floor",
                "title": "2楼",
                "isHidden": true,
            }],
            "bindAll": false,
            "isHidden": true,
            "field": "2-unit",
            "title": "2单元",
            "id": "2",
        }],
        deepList: [],
        deepListOne: []
    },
    
    onShow: function () {
        this.checkForChecked()
    },

    
    checkForChecked() {
        var data = this.data.menuTree

        // 获取所有被选中的节点
        var checkednodes = this.getDeep(data)
        // 获取所有选中节点的父节点
        checkedNodes.forEach(element => {
            var tmp = this.getParentsById(data, element.id)
            if (tmp != undefined && tmp.length > 0) {
                // 最后一级选中,默认展开和选中父级菜单
                tmp.forEach(element => {
                    element.isHidden = false
                    element.checked = true
                })
            }
        })

        this.setData({
            menuTree: data
        })
    },
    // 递归 - 根据id获取所有父节点
    getParentsById(list, id) {
        for (let i in list) {
            if (list[i].id == id) {
                return [list[i]]
            }
            if (list[i].children) {
                let node = this.getParentsById(list[i].children, id);
                if (node !== undefined) {
                    return node.concat(list[i])
                }
            }
        }
    },
    // 递归 - 根据id获取当前节点对象
    getNodeById(data, id, newNodes = []) {
        data.forEach(element => {
            // 匹配到节点
            if (element.id === id) {
                newNodes.push(element)
            }
            if (element.children) {
                this.getNodeById(element.children, id, newNodes)
            }
        })
        return newNodes;
    },

    // 递归 - 根据id获取所有子节点,(其实就是先获取当前id的节点对象,然后取当前对象,注意这里返回的是数组)
    getChildrenById(data, id, newNodes = []) {
        var list = data.children
        if (list != undefined) {
            list.forEach(element => {
                newNodes.push(element)
                if (element.children) {
                    this.getChildrenById(element, id, newNodes)
                }
            })
        }
        return newNodes;
    },

    // 递归 - 获取所有选中节点
    getDeep(data, newCheckedNodes = []) {
        data.forEach(element => {
            if (element.checked) {
                newCheckedNodes.push(element)
            }
            if (element.children) {
                this.getDeep(element.children, newCheckedNodes)
            }
        })
        return newCheckedNodes
    },

    // 递归 - 根据节点id获取兄弟所有节点
    getBrotherNodesById(list, id) {
        // 非顶级节点:获取节点父节点对象里的children
        var parentNodes = this.getParentsById(list, id)
        if (parentNodes && parentNodes.length >= 2) {
            return parentNodes[1].children
        }
        // 顶级节点:第一级是自己,从原始数组中遍历第一层即可
        return list

    },

    // 根据当前节点id,获取及所有的父级兄弟节点的所有父节点
    getParentBrotherAllNodesById(list, id) {
        var result = []
        // 1、获取当前节点id父节点的父节点
        var parentNodes = this.getParentsById(list, id)

        // 小于3表示当前父节点是顶级节点
        if (parentNodes.length < 3) {
            return parentNodes[parentNodes.length - 1]
        }
        var testNode = parentNodes[2];
        // 2、获取父节点的父节点所有兄弟节点
        var children = testNode.children
        children.forEach(element => {
            var parentNodesById = this.getParentsById(list, element.id)
            if (parentNodesById.length >= 2) {
                // js 数组中添加多个元素 简单的方法 push(...[])
                result.push(...(parentNodesById.slice(0, parentNodesById.length - 1)))
            }
        });
        return result;
    },

    
    checkboxChangeBindAll(e) {
        var index = e.currentTarget.dataset.index;
        var index2 = e.currentTarget.dataset.index2;
        var list = this.data.menuTree
        if (index2 == undefined) {
            list[index].bindAll = !list[index].bindAll
        }
        if (index2 != undefined) {
            list[index].children[index2].bindAll = !list[index].children[index2].bindAll
        }

        console.log(this.data.menuTree);
    },
    checkboxChange(e) {
        // console.log(e);
        console.log('checkbox发生change事件,携带value值为:', e.detail.value)
        const values = e.detail.value
    },


    
    checkboxChangeAll(e) {
        var id = e.currentTarget.dataset.id;
        var data = this.data.menuTree
        var node = this.getNodeById(data, id)
        var childrenNodes = this.getChildrenById(node[0], id)

        // 1、子节点点选中状态-跟随父节点移动
        node[0].checked = !node[0].checked
        // 节点下面的所有子节点跟随父节点的选中状态
        childrenNodes.forEach(element => {
            element.checked = node[0].checked
        })

        // 2、父节点选中状态,子节点都没选中,父节点默认不选中,子节点有一个选中,父节点也选中
        // 获取同级兄弟节点
        var bortherNodes = this.getBrotherNodesById(data, id)

        // 3、同级都选中
        var allChecked = false
        bortherNodes.forEach(element => {
            if (element.checked) {
                allChecked = true
            }
        })

        // 获取节点id所有父节点
        var parentNodes = this.getParentsById(data, id)
        if (parentNodes.length > 1) {
            if (allChecked) {
                // 下标index=0的节点是其本身,这里跳过
                for (let index = 1; index < parentNodes.length; index++) {
                    const element = parentNodes[index];
                    element.checked = true
                }
            }else{
                parentNodes[1].checked =false
            }
        }

        // 4、同级都未选中
        if (!allChecked) {
            var allNoChecked = false
            //  根据当前节点id,获取除去顶级节点的所有的父级兄弟节点的所有父节点
            var parentBother = this.getParentBrotherAllNodesById(data, id)
            console.log(parentBother);
            if (parentBother.length > 1) {
                parentBother.forEach(element => {
                    if (element.checked) {
                        allNoChecked = true
                    }
                });
            }
            console.log(allNoChecked);
            // console.log(parentBother);
            if(!allNoChecked){
                parentNodes.forEach(element => {
                    element.checked=false
                });
            }
        }


        this.setData({
            menuTree: data
        })
        // console.log(this.data.menuTree);
    },
    
    openAndHide(e) {
        var id = e.currentTarget.dataset.id;
        var list = this.data.menuTree

        console.log(id);
        // 根据 id 获取选中节点的对象
        var node = this.getNodeById(list, id)
        // 根据 id 获取选中节点下的所有子节点
        var res = this.getChildrenById(node[0], id)
        // 包含当前id节点本身
        res.push(node[0])

        // 遍历选中节点(及自己)是否展开
        res.forEach(element => {
            element.isHidden = !element.isHidden
        })

        this.setData({
            menuTree: list
        })

    }
})

2、treeMenu2.JSON

{
  "usinGComponents": {}
}

3、treeMenu2.WXMl

这里其实写的有问题,我主要写java的,前端用的不多,哪个高手指点一下,wxml 文件怎么样能递归呢,
我这里直接最笨的方法,三层for…,

<view class="divCSS5-max">
  <view class="page-section ">
    <view style="padding-bottom:10px">设备选择列表:{{menuTree.length}}</view>
    <view class="weui-cells weui-cells_after-title "></view>
    <view>
      <!-- 第一层 -->
        <block class="weui-cell weui-check__label line-center" wx:for="{{menuTree}}" wx:for-index="index"
          wx:for-item="item" wx:key="id">
          <view class="paddingBottom_10 "></view>
          <view class="paddingLeft_10">
          <view class="treeMenuCenter">
            <checkbox-group bindchange="checkboxChangeAll" data-index="{{index}}" data-id="{{item.id}}" >
              <checkbox value="{{item.field}}"  checked="{{item.checked}}" />
              </checkbox-group>
            <!-- 箭头图标 -->
            <view class="treeMenuCenter"  bindtap="openAndHide" data-id="{{item.id}}" data-index="{{index}}"  >
            <image wx:if="{{item.isHidden == true}}"  class="icon-chioce" src="{{menuTreeImgLeft}}"></image>
            <image wx:if="{{item.isHidden == false}}"  class="icon-chioce" src="{{menuTreeImgBottom}}"></image>
            <text style="color:black" 
              decode="{{true}}">&nbsp;{{item.title}} &nbsp;</text>
              </view>
              <!-- <checkbox-group bindchange="checkboxChangeBindAll" data-index="{{index}}"  >
              <checkbox  checked="{{item.bindAll}}"   />绑定单元
              </checkbox-group> -->
          </view>
           
          </view>
          <!-- 第二层 -->
          <view class="" hidden="{{item.isHidden}}" wx:for="{{item.children}}" wx:for-index="index2" wx:for-item="item2"
            wx:key="id">
            <view class="paddingLeft_20 ">
            <view class="treeMenuCenter">
            <!-- <view class="dashedStyleWidth_40"></view> -->
            <checkbox-group bindchange="checkboxChangeAll" data-id="{{item2.id}}" data-index="{{index}}" data-index2="{{index2}}" >
            <checkbox value="{{item2.field}}" checked="{{item2.checked}}" />
            </checkbox-group>
              <!-- 箭头图标 -->
              <view class="treeMenuCenter"  bindtap="openAndHide"  data-id="{{item2.id}}"
               data-index="{{index}}" data-index2="{{index2}}" >
              <image wx:if="{{item2.isHidden == true}}" class="icon-chioce" src="{{menuTreeImgLeft}}"></image>
              <image wx:if="{{item2.isHidden == false}}"   class="icon-chioce" src="{{menuTreeImgBottom}}"></image>
              <text style="color:#0094aa"    decode="{{true}}">&nbsp; {{item2.title}}&nbsp; &nbsp;</text>
            </view>
              <!-- <checkbox-group bindchange="checkboxChangeBindAll" data-index="{{index}}" data-index2="{{index2}}" >
              <checkbox  checked="{{item2.bindAll}}"  />绑定楼层
              </checkbox-group> -->
            </view>
              
            </view>
            <!-- 第三层 -->
            <block class="" wx:for="{{item2.children}}" wx:for-item="item3"  wx:for-index="index3" wx:key="id">
              <view class="paddingLeft_30 " hidden="{{item2.isHidden}}">
                <!-- <view class="dashedStyleWidth_80"></view> -->
                <checkbox-group bindchange="checkboxChangeAll" data-id="{{item3.id}}"
                 data-index="{{index}}" data-index2="{{index2}}"  data-index3="{{index3}}" >
                <checkbox value="{{item3.field}}" checked="{{item3.checked}}" />
                {{item3.title}}
              </checkbox-group>
               
              </view>
            </block>
          </view>
          <view class="paddingBottom_10 "></view>
          <view class="weui-cells weui-cells_after-title "></view>
        </block>
    </view>
  </view>
</view>

4、treeMenu2.WXSS


@import '../../../lib/weui.wxss';

.empty{
  padding: 5px 0px;
}
.paddingLeft_10{
  padding-left: 10px;
  padding-bottom: 5px;
}

.paddingLeft_20{
  padding-left: 40px;
  padding-bottom: 5px;
}

.paddingLeft_30{
  padding-left: 80px;
  padding-bottom: 5px;
}

.paddingBottom_10{
  padding-top: 10px;
}
.line-center{
  display: flex;
  align-items: center;
  justify-content: center;
  flex-flow: column;
}
  
checkbox .wx-checkbox-input.wx-checkbox-input-checked {
  background: #0094aa;
}

checkbox .wx-checkbox-input.wx-checkbox-input-checked::before{
  color:#fff; 
}

.treeMenuCenter{
  display: flex;
  align-items: center;
}

.dashedStyleWidth_80{
  margin-left: 10px;
  margin-right: 5px;
  width: 80px;
  height: 0px;
  border: 0.5px dotted gray;
}

.dashedStyleWidth_40{
  margin-left: 10px;
  margin-right: 5px;
  width: 40px;
  height: 0px;
  border: 0.5px dotted gray;
}

   
.icon-chioce {
  height: 15px;
  width: 15px;
  padding-top: 10px;
  padding-bottom: 10px;
  background-color: fff;
 }

五 、最后

哪个大侠指点一下,wxml如何递归就完美了

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持编程网。

--结束END--

本文标题: 微信小程序实现多层级复选框菜单

本文链接: https://lsjlt.com/news/164512.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

猜你喜欢
  • 微信小程序实现多层级复选框菜单
    目录一、背景二 、效果展示三、功能点四、代码实现五 、最后本文实例为大家分享了微信小程序自定义多层级复选框菜单的具体代码,供大家参考,具体内容如下 一、背景 因客户需要,有一个功能是...
    99+
    2024-04-02
  • 微信小程序实现双层嵌套菜单栏
    最近在做的项目有这样一个需求,也不太好描述,就是有两个顶部菜单栏,每个二级菜单栏的item都有自己页面,每个页面都可以通过左右滑动来切换,第一个想到的实现方法就是双层swiper嵌套...
    99+
    2024-04-02
  • 小程序实现自定义多层级单选和多选
    本文实例为大家分享了小程序实现自定义多层级单选和多选的具体代码,供大家参考,具体内容如下 效果: ps:这儿是用自定义的下拉框,我把它封装成了一个组件 wxml <vie...
    99+
    2024-04-02
  • 微信小程序实现多选框全选操作
    本文实例为大家分享了微信小程序实现多选框全选的具体代码,供大家参考,具体内容如下 test.wxml <view class="container">     <!...
    99+
    2024-04-02
  • 微信小程序如何实现双层嵌套菜单栏
    这篇文章主要介绍“微信小程序如何实现双层嵌套菜单栏”,在日常操作中,相信很多人在微信小程序如何实现双层嵌套菜单栏问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”微信小程序如何实现双层嵌套菜单栏”的疑惑有所帮助!...
    99+
    2023-07-02
  • 微信小程序实现联动菜单
    最近为了实现课程设计,也做了一些前端的东西,今天想要做一个联动菜单来实现一些功能。实现了,也来做做笔记。 第1步:了解一下 左右侧菜单其实简单来讲就是把一个区域分成左右两个部分。关于...
    99+
    2024-04-02
  • 微信小程序实现收缩式菜单
    本文实例为大家分享了微信小程序实现收缩式菜单的具体代码,供大家参考,具体内容如下 wxml文件 <view class="page"> <!--分类 -->...
    99+
    2024-04-02
  • 微信小程序实现单选按钮
    本文实例为大家分享了微信小程序实现单选按钮的具体代码,供大家参考,具体内容如下 逻辑 单选框的逻辑比较简单,把所有的元素遍历出来,等到点击单选按钮的时候,当value值与遍历变量值一...
    99+
    2024-04-02
  • 微信小程序实现字母索引菜单
    本文实例为大家分享了微信小程序实现字母索引菜单的具体代码,供大家参考,具体内容如下 wxml文件 <view class="container"> <view c...
    99+
    2024-04-02
  • 微信小程序自定义单选框样式实现单选功能
    本文实例为大家分享了微信小程序自定义单选框样式实现单选功能的具体代码,供大家参考,具体内容如下 实现效果: 选择小车时,其他类型的车取消选中。 具体思路: 用数组存几种类型车的数据...
    99+
    2024-04-02
  • 微信小程序实现下拉选项框
    本文实例为大家分享了微信小程序实现下拉选项框的具体代码,供大家参考,具体内容如下 效果图 test.js   data: {     shows: false, //控制下拉列表...
    99+
    2024-04-02
  • 微信小程序实现简单搜索框
    本文实例为大家分享了微信小程序实现简单搜索框的具体代码,供大家参考,具体内容如下 app.json {   "pages":[     "pages/index/index"   ]...
    99+
    2024-04-02
  • 微信小程序自定义复选框
    本文实例为大家分享了微信小程序自定义复选框的具体代码,供大家参考,具体内容如下 1、效果  2、wxml <checkbox-group bindchange="c...
    99+
    2024-04-02
  • 微信小程序实现点餐小程序左侧滑动菜单
    目录前言一、初识scroll-view二、左侧导航三、右侧滑动前言 最近在帮亲戚做一款微信的点餐小程序,以前从没有接触过小程序的我只能现做现卖。一边看文档一边实践尝试,在进行到点菜模...
    99+
    2024-04-02
  • 微信小程序如何实现收缩式菜单
    这篇“微信小程序如何实现收缩式菜单”文章的知识点大部分人都不太理解,所以小编给大家总结了以下内容,内容详细,步骤清晰,具有一定的借鉴价值,希望大家阅读完这篇文章能有所收获,下面我们一起来看看这篇“微信小程序如何实现收缩式菜单”文章吧。wxm...
    99+
    2023-07-02
  • 微信小程序实现多列选择器
    本文实例为大家分享了微信小程序实现多列选择器的具体代码,供大家参考,具体内容如下 <picker class="picks" mode="multiSelector" bind...
    99+
    2024-04-02
  • 微信小程序实现简单弹框效果
    本文实例为大家分享了微信小程序实现简单弹框的具体代码,供大家参考,具体内容如下 1、页面结构 <!-- 遮罩层 --> <view>     <view...
    99+
    2024-04-02
  • 微信小程序实现性别单选效果
    本文实例为大家分享了微信小程序实现性别单选的具体代码,供大家参考,具体内容如下 效果图: 代码: html: <view class="inputbox">      ...
    99+
    2024-04-02
  • 微信小程序单选框组应用详解
    本文实例为大家分享了微信小程序单选框组应用的具体代码,供大家参考,具体内容如下 需求概述 有一个核选项数组,里面存放着核选项名称、内容、ID、选择状态。选择状态有未选择、符合、不符合...
    99+
    2024-04-02
  • 微信小程序如何实现字母索引菜单
    本篇内容介绍了“微信小程序如何实现字母索引菜单”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!wxml文件<view clas...
    99+
    2023-07-02
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作