微信小程序实现简单的树形选择控件------treeSelect

2023-11-07

前段时间公司突然要写小程序,项目中有一个树形控件。我找了很久的插件和框架。没有发现小程序能用的。只能硬着头皮自己写。

老规矩,先贴图
在这里插入图片描述

  • 为什么要特意强调此图标呢?
  • 因为该图标为中间状态。此处是我后期要优化的地方,在下面的代码中还未实现。我有了初步的思考。
    我的代码中设定(以网络部为例)
  • 0 该部门成员全部未选中
  • 1 该部门成员全部选中
  • -1 该部门成员至少选中一人切少于部门总人员数

好了,下面我们来实现树形结构的全选和零选中状态

  • 首先是树形组件的代码
    components文件夹下创建tree-select文件夹,选择新建component。命名为index

index.wxml文件

<view id="treeItem">
  <block wx:for="{{treeList}}" wx:key="deptId">
    <view  class="tree-item" style="margin-left: {{depth*40}}rpx" data-id="{{item.deptId}}" data-is-check="{{item.isCheck}}" catchtap="handleClick" >
      <!-- 全选 -->
      <view class="iconfont iconxuanzhong" wx:if="{{item.isCheck == 1}}" style="color: #007AFF" ></view>
      <!-- 未选中 -->
      <view class="iconfont iconweixuanzhong1" wx:if="{{item.isCheck == 0}}" style="color:#000" ></view>
    </view>
    <!-- children -->
    <view wx:if="{{item.children}}">
      <tree-select treeList="{{item.children}}" treeArray="{{treeArray}}" depth="{{depth+1}}" catchhandleClick="treeClick" id="treeItem"></tree-select>
    </view>
  </block>
</view>

树形组件主要用的就是递归。所以上面组件中我在组件中又调用组件自身。通过depth来判断层级关系,来实现数据的缩进。treeList为页面中传进来的人员数据,treeArrary为我清洗数据之后传过来的初始的人员选中状态的数组

index.json*

{
  "component": true,
  "usingComponenuts": {
    "tree-select": "/components/tree-select/index"
  }
}

此处要在usingComponenuts中引入组件自身

index.js

  /**
   * 组件的属性列表
   */
  properties: {
    treeList: {
      type: Array,
      value: []
    },
    depth: {
      type: Number,
      value: 0
    },
    treeArray: {
      type: Array,
      value: []
    }
  },
  /**
   * 组件的初始数据
   */
  data: {
    realTreeMap: new Map(),
  },

因为小程序页面中不能直接传递map对象给组件,所以我在组件中定义了map对象。他的主要作用是用来修正人员的真实选中状态。

 ready(){
    const {
      treeList,
      treeArray,
    } = this.properties;
    this.setData({
      treeList,
      treeArray,
    })
  },

在这里插入图片描述

此处,获取页面中传递过来的数据

    // 获取当前真实状态键值Map结构
    initRealTreeMap() {
      // 获取真实状态键值列表
      const {treeArray} = this.data
      // 生成真实状态键值Map结构
      var mRealTreeMap = new Map()
      treeArray.forEach(item => {
        mRealTreeMap.set(item.key, item.value);
      })
      // 给组件内部变量赋值真实状态Map结构
      this.setData({
        realTreeMap: mRealTreeMap
      })
    },

在这里插入图片描述

这里有一个要注意的就是,你点击某一项数据时,只能获取到与他同级的所有数据。比如:点击网络部,你拿到的数据就是 杨xx,马xx,营销部,网络部这四项数据

    handleClick(e){
      // 获取当前真实状态键值Map结构
      this.initRealTreeMap()

      // 获取当前的树形结构列表,真实状态键值列表,真实状态键值Map结构
      const { treeList, treeArray, realTreeMap } = this.data

      // 获取点击项id及其前一个状态
      const t = this.selectAllComponents('#treeItem');
      const { id, isCheck }  = e.currentTarget.dataset

      // 根据点击项id获取点击项及子节点id集合
      const idSet = new Set()
      this.getData(treeList, id, idSet)

      // 修改TreeList点击项及其子节点选中状态,但是,平级别的其他项及子项还是原始数据
      // this.setStatus(treeList, idSet, !isCheck)
      this.setStatus(treeList, idSet, !isCheck)


      // 修正TreeList除点击项及其子节点之外的其他平级及子节点项状态为真实状态
      this.repairTreeList(id, treeList)
      treeArray.forEach(item => {
        item.value = realTreeMap.get(item.key)
      })

      // 赋值给组件内部三大核心变量,树形结构列表,真实状态键值列表,真实状态键值Map结构
      this.setData({
        treeList,
        treeArray, 
        realTreeMap
      })
      // 触发向上通信传递事件,向父组件传递变量,主要为TreeList和TreeArray
      this.triggerEvent('handleClick', { id, isCheck, treeList, treeArray});
    },

因为treeList 所传递的数据为所选中的部门的平级数据,所以每次点击后之前操作的数据就会被重置为初始状态。所以用 repairTreeList来修正数据的真正状态

    // 【递归函数】由于TreeList递归传递渲染,导致平级非点击项数据为原始状态,此方法用于修正TreeList数据状态为真实状态,真实状态保存在treeArray及RealTreeMap中
    repairTreeList(id, treeList) {
      treeList.forEach(item => {
        item.isCheck = this.data.realTreeMap.get(item.deptId)
        if(this.hasValidChildren(item)) {
          this.repairTreeList(id, item.children)
        }
      })
    },
    // 父组件向子组件传值
    treeClick(e){
      // 接收子组件向上传递的变量
      const { id, isCheck, treeList, treeArray } = e.detail
      // 设置真实状态键值列表
      this.setData({
        treeArray
      })
      // 子组件内嵌套组件,循环向上触发通信传递事件,向父组件传递变量,主要为TreeArray
      this.triggerEvent('handleClick', { id, isCheck, treeList, treeArray });
    },

setStatus方法 将getData()方法返回的ids集合的id设为选中状态

    // 【递归函数】切换选中状态
    setStatus(dataTree, idSet, isCheck) {
      for (let i = 0; i < dataTree.length; i += 1) {
        // 遍历节点列表,若切换集合包含该节点,则切换选中状态
        if(idSet.has(dataTree[i].deptId)) {
          // 修正选中项状态
          this.resetCheckStatus(dataTree[i], isCheck)
          // 若当前节点的子节点列表不为空,则遍历子节点
          if (this.hasValidChildren(dataTree[i])) {
            let children = dataTree[i].children
            children.forEach( item => {
              // 若切换集合包含该节点,则切换子节点选中状态
              if(idSet.has(item.deptId)) {
                // 修正子节点选中状态
                this.resetCheckStatus(item, isCheck)
              }
              // 若子节点的子节点列表不为空,则递归调用切换选中状态
              if(this.hasValidChildren(item)) {
                this.setStatus(children, idSet, isCheck)
              }
            })
          }
        }
      }
    },
    // 修正选中项状态
    resetCheckStatus(item, isCheck) {
      // 修改TreeList里的数据,用于渲染
      item.isCheck = isCheck
      // 修改RealTreeMap里的数据,保存真实状态
      this.data.realTreeMap.set(item.deptId, isCheck)
      // 优化后放到修正RepairTreeList完成之后,防止重复遍历造成性能损耗
       修改treeArray里的数据,保存真实状态,用于组件间传值
      // treeArray.forEach(i => {
      //   i.value = this.data.realTreeMap.get(i.key)
      // })
    },

getData方法实现的逻辑是当部门被选择时,他下面的部员都被选中,部门被取消选中时,部员也取消选中,并返回选中的人员的id集合

    // 【递归函数】获取点击项及其子节点项id集合,即切换集合
    getData(dataTree, id, idSet) {
      // 由于dataTree为id项的同级别列表,因此遍历同级别列表,匹配其中id项及其子节点
      for (let i = 0; i < dataTree.length; i += 1) {
        if (dataTree[i].deptId === id) {
            // id匹配,加入切换集合
            idSet.add(id)
            if (this.hasValidChildren(dataTree[i])) {
              // 存在子节点列表
              let children = dataTree[i].children
              // 遍历其子节点列表,将其子节点加入切换集合
              children.forEach(item=> {
                idSet.add(item.deptId)
                // 子节点存在子节点列表,则递归调用函数,获取其子节点的子节点列表及其包含项
                if(this.hasValidChildren(item)) {
                  // 注意,此处传递item及其同级别节点列表,而不是传递其子节点列表
                  this.getData(children, item.deptId, idSet);
                }
              })
            }
        }
      }
      return idSet
    },

此方法用来判断数据的children不为空

    // 判断对象是否存在有效的子节点列表
    hasValidChildren(item) {
      return item.children != undefined && item.children.length > 0
    },
  • 下面为引入组件的页面中的代码
  • wxml页面
<tree-select treeList='{{treeData}}' treeArray='{{treeArray}}' catchhandleClick="treeClick" depth="{{0}}" id="treeItem"></tree-select>
  • js页面
 // 将树形列表结构转化为一级列表结构,传递进入组件中,便于遍历、比较和赋值
  getTreeKeyValueArray(data, mTreeArray) {
    data.forEach(item => {
      mTreeArray.unshift({
        'key': item.deptId,
        'value': item.isCheck
      })
      // 若存在子节点列表,则递归处理数据
      if(this.hasValidChildren(item)) {
        this.getTreeKeyValueArray(item.children, mTreeArray)
      }
    })
  },
  treeClick(e){
    // 接收子组件向上传递的变量
    const { id, isCheck, treeList, treeArray } = e.detail
    // 更新设置树形结构列表及真实状态键值列表
    this.setData({
      treeList, 
      treeArray
    })
    this.getCheckedIds(treeArray)
  },

到此,这个组件就全部完成了。
后续中间状态完成以后,我还会继续更新。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

微信小程序实现简单的树形选择控件------treeSelect 的相关文章

  • 合宙Air724UG LuatOS-Air LVGL API控件-图片 (Image)

    图片 Image 图片IMG是用于显示图像的基本对象类型 图像来源可以是文件 或者定义的符号 示例代码 创建图片控件 img lvgl img create lvgl scr act nil 设置图片显示的图像 lvgl img set s
  • C# 执行 .bat 文件

    string path E a bat Process pro new Process FileInfo file new FileInfo path pro StartInfo WorkingDirectory file Director

随机推荐

  • 在react hook里使用mobx(配置mobx依赖)

    在powershell里安装依赖 直接npm i mobx或者npm i mobx react是会报错的 npm i mobx mobx react save save是下载到 dependencies 里 npm i mobx react
  • 图像边缘及matlab实现

    图像边缘是图像的重要特征 是图像中特性 如像素灰度 纹理等 分布的不连续处 图像周围特性有阶跃变化或屋脊状变化的那些像素集合 图像的边缘部分集中了图像的大部分信息 一幅图像的边缘结构与特点往往是决定图像特质的重要部分 图像边缘的另一个定义是
  • Spring Boot + Vue的网上商城之物流系统实现

    Spring Boot Vue的网上商城之物流系统实现 思路 当构建一个物流系统时 我们可以按照以下步骤进行 设计数据模型 首先确定系统中需要存储的数据 例如物流公司信息 物流订单信息等 根据需求设计相应的数据模型 包括实体类和数据库表结构
  • 软件工程考试归纳知识点

    软件工程 第一章 什么是软件 软件是计算机系统中与硬件子系统相互依存的另一个子系统 是一个包含程序及其文档资料的完整集合 提供了用户与硬件子系统之间的接口 软件的特征 1 软件固有的特性 复杂性 抽象性 依赖性 软件使用特性 2 软件生产特
  • Python之可变参数,*参数,**参数,以及传入*参数,进行解包

    1 定义了一个需要两个参数的函数 def print str first second print first print second if name main print str hello world 如果传一个参数调用 print
  • Blink 帮助文档 编译

    个人使用的是Centos7 1 安装rvm 参考 http rvm io rvm install gpg keyserver hkp pool sks keyservers net recv keys 409B6B1796C275462A1
  • Rocksdb Compaction原理

    概述 compaction主要包括两类 将内存中imutable 转储到磁盘上sst的过程称之为flush或者minor compaction 磁盘上的sst文件从低层向高层转储的过程称之为compaction或者是major compac
  • c++中引用及指针详解

    这里写目录标题 1 指针 1 1 什么是指针 指针的本质 指针与地址 程序中如何声明指针以及如何使用运算符 和 1 2 指针有什么作用 指针与函数参数 2 引用 2 1 什么是引用 2 2 引用的规则 2 3 引用和数组 引用的数组 非法
  • 在linux中,使用sh文件脚本启动jar项目

    使用方法 sh 执行脚本 sh start stop restart status sh文件内容 APP NAME XXXX jar 使用说明 用来提示输入参数 usage echo Usage sh 执行脚本 sh start stop
  • SpringBoot HTTP接口GET请求

    HTTP接口get请求 注解使用 1 RequestMapping 来映射请求 也就是通过它来指定控制器可以处理哪些URL请求 2 PathVariable 将 URL 中的占位符绑定到控制器的处理方法的参数中 占位符使用 括起来 3 Ge
  • 完全数(Perfect number),又称完美数或完备数,是一些特殊的自然数。 它所有的真因子(即除了自身以外的约数)的和(即因子函数),恰好等于它本身。 例如:28,它有约数1 style="">

    题目 完全数 Perfect number 又称完美数或完备数 是一些特殊的自然数 它所有的真因子 即除了自身以外的约数 的和 即因子函数 恰好等于它本身 例如 28 1 2 4 7 14 28 给定数计算n以内完全数的个数 计算范围 0
  • 《PRML》学习笔记2.2——多项式分布和狄利克雷分布

    上回讲完了伯努利分布 二项分布和Beta分布 以及从最大似然估计的非参数化思想和引入共轭先验 使得参数变成一个变量 建模求解的参数化方法两方面介绍了求解模型参数的方法 没有读过的朋友可以参考 PRML 学习笔记2 1 伯努利分布 二项分布和
  • three.js应用cannon物理引擎设置物体的相互作用

    一 cannon物理引擎介绍 cannon官网地址 https pmndrs github io cannon es Cannon js 是一个基于 JavaScript 的开源 3D 物理引擎 可以用于开发和模拟真实世界中的物理效果 它提
  • 机器学习-分类-朴素贝叶斯算法

    三 朴素贝叶斯算法 朴素贝叶斯算法是基于贝叶斯定理与特征条件独立性假设的分类方法 1 原理 1 贝叶斯定理 2 特征条件独立性假设 给定一个数据集 x y 每个样本x包含n维特征 类标签集合y包含N个类别 现给定一个新样本x 需要判断它属于
  • grub rescue修复方法

    问题描述 开机显示 GRUB loading error unknow filesystem grub rescue gt 造成该问题的原因 1 直接在window下格式化ubuntu的分区 2 调整磁盘 利用工具合并 修改 删除分区 是磁
  • python爬虫封装函数_爬虫验证码的几种处理方式,已封装成类,文章末尾有源码!...

    最近事情其实挺多了 打了一下蓝桥杯的比赛 还在准备着一些证书的考试 关于爬虫之类的博客都搁着了一段时间了 关于我自己确实有点退步了 实属不该 其实我自己也是在想 大三了 到底我是要去考研 还是依然像这样更新换代的学技术 再或者 继续钻爬虫这
  • Oracle中char、varchar、varchar2的区别

    1 从字符长度上来分 var可以保存2000个字符 varchar 同样保存2000个字符 varchar 保存4000个字符 2 从字符长度是否可变上来分 var和varchar长度一样 但是varchar是可变的var是不可变的 var
  • 【Linux】list_for_each_entry用法

    参考 http blog sina com cn s blog 5e99b41e0100rxgf html http hi baidu com shiftedmind blog item 1a7c8381e6a67fa56d8119da h
  • udevadm命令详解

    udevadm 后接一个命令和命令指定选项 它控制了udev运行的行为 处理内核事件 控制事件队列 并且提供简单的调试机制 选项 debug 打印错误信息 version 打印版本信息 help 帮助文档 udevadm info opti
  • 微信小程序实现简单的树形选择控件------treeSelect

    前段时间公司突然要写小程序 项目中有一个树形控件 我找了很久的插件和框架 没有发现小程序能用的 只能硬着头皮自己写 老规矩 先贴图 为什么要特意强调此图标呢 因为该图标为中间状态 此处是我后期要优化的地方 在下面的代码中还未实现 我有了初步