iview+treeSelect组件,我是如何一步步手动实现全选功能的

news/2024/7/7 19:35:27

如果我掏出下图,阁下除了私信我加入学习群,还能如何应对?

在这里插入图片描述

正文开始

  • 前言
  • 一、历史问题
  • 二、通过监听select事件实现全选不靠谱!!!
  • 三、 通过外部事件控制树选择组件
  • 四、render函数创建组件
  • 4.1 不得不说的h函数
  • 4.2 如果条件允许,请使用jsx
  • 总结


前言

因为种种历史原因,我们一直选择的vue前端框架是iview,而非element,在老版的iview中,treeselect(树选择组件)一直都是半成品,后来团队买了iview pro版,树选择组件虽然能够使用,但功能仍显单一,缺少全选功能。

现在项目要求实现全选,就只能自己动手了。

心情烦躁者,会觉得一多半文章在讲废话,请直接下拉到最后查看实现方式。


一、历史问题

研究早期iview版本的treeselect源码,我们可以将它和数据有关系的部分分为两类:

  1. 树形图数据
  2. select选项数据

select选项数据其实又可以分为两部分:
3. 下拉框中选项部分;
4. input中的tag标签显示部分。(看着像input,其实是渲染成div了,为了便于理解,就这么称呼了)

如图所示:
在这里插入图片描述
这几部分数据大致的逻辑如下:
1.渲染树形图数据,在下拉框中形成树形图。
2.点击树形图的数据,会触发select的方法,选中点击的数据
3.select方法被触发后,会触发input方法,修改tag标签的显示。(这个是真的input方法,形如:vm.$emit(‘input’,xxxxx))

逻辑很简单,不简单的是,当数据增加、删除、改变时,这三个数据逻辑之间互相监听,来回改变,最终为了实现三项数据的联动,导致数据变化监听十分复杂。

这就导致我们如果要实现全选功能,最好就不要再去通过监听select事件来实现。

二、通过监听select事件实现全选不靠谱!!!

iview pro版本是采用函数组件的方式,查看它源码后,会发现虽然代码清爽了许多,但是三者之间还是联动。

所以我不想再采用监听select的方式。原因有二:

  1. 监听select,触发某个条件后再手动为select赋值,会继续触发监听,形成死循环。
  2. 上面的问题可以解决,但代码过多,并无必要,而且需要修改源码,不利于后续框架升级。

切记:研究新旧版select代码的过程绝对不舒服,希望大家有所了解就行,不要好奇去看它代码,会被各种监听搞吐的!!!

三、 通过外部事件控制树选择组件

既然不能监听内部的select事件,那我通过和树组件并不想关的一个事件,调用select提供的方法,是不是就能避免修改源码,并且不会形成死循环。

尝试后,发现是可以的。具体操作如下:

  1. 创建一个普通的树组件,其中树形图数据为treeData,组件的v-model绑定的数据为:argStrList,代码如下
<TreeSelect ref="treeSelect" :max-tag-count="3" multiple v-model="argStrList" :data="treeData"/>
  1. 在组件毫不相关的地方,创建一个button,点击事件中修改argStrList,并做个延迟,方便我们有时间打开下拉框查看变化。代码如下:
     setTimeout(()=>{
              this.argStrList=allValueArr
            },3000)

allValueArr是我创建的一个value值数组,具体是什么,根据各自项目情况而定。

  1. 打开下拉框后,发现过了两三秒,下拉框中对应的选项被选择,input中的tag也相应维护,说明外部事件控制select来触发创建,并不会产生额外的副作用。

但是这种方式也实在太不优雅了,所以就想到在下拉框里渲染元素和事件,但是并不和select本身的元素和事件关联。treeselect组件并没有直接提供在树形图里面添加其它元素的方式。但树选择组件是基于tree组件的,tree组件提供了render函数自定义元素内容。

所以我们要做的就是在tree树形图中,创建一个能被我们自由控制的元素和事件。

四、render函数创建组件

4.1 不得不说的h函数

不得不说,h函数很多场景很好用,但在反人类的道路上一去不返,我并不支持这种写法,所以只列代码,不讲解:

 render: (h, { root, node, data }) => {
          return h('span', {
            style: {
              display: 'inline-block',
              width: '100%'
            }
          }, [
            h('span', [
              h('span', data.title)
            ]),
            h('span', {
              style: {
                display: 'inline-block',
                float: 'right',
                marginRight: '32px'
              }
            }, [
              h('Checkbox', {
                style: {
                },
                on: {
                  'on-change': () => {
                    this.argStrList.push('1400344119453511682')
                  }
                }
              }),
              h('span','全选')
            ])
          ]);
        },

4.2 如果条件允许,请使用jsx

Babel版本3.4.0开始已经支持jsx,相当老的版本了,如果项目里插件版本过低,请升级。

树形图root节点的全部代码如下:

 let root = {
        id: '0',
        name: '组织架构树',
        type: 0,
        render:(h,{root,node,data})=>{
          const key='value' || "id"
          const allValueArr=_.map(_.map(root,'node'),key)
          const checkChange=(e)=>{
            if(e){
              this.argStrList=allValueArr
            }else{
              this.argStrList=[]
            }
          }
          return(
            <div>
              <Checkbox vOn:on-change={(e)=>checkChange(e)}>{data.title}</Checkbox>
            </div>
          )
        }
      }

这段代码主要就是在root节点上渲染了一个checkbox,并添加事件。如图:

在这里插入图片描述

注意点:

  1. jsx语法请查看github官网文档;
  2. _.map是loadash提供的api,作用是把所有树形节点的value取出来组成数组allValueArr;

总结

  1. treeSelect组件内部各种互相监听太复杂了,很容易动一处爆两处bug,所以慎动。
  2. 内部监听事件解决不了,就做个外部事件。然后用黑科技,把外部事件做到tree里,看起来好像是本身的一部分一样。这样做出来的全选功能,就只在treedata数据里增加一个属性,对项目代码和treeselect组件代码影响都是最小的。
  3. treeselect这种实现方式应该引以为戒,太难维护了。我虽然没有实操,但是这种很多类数据之间有关联的场景,应该尽可能用单例模式,创建个类或者自执行的闭包,相当于模拟一个三两个组件共享的小型状态管理工具,把数据维护到内存。尾大不掉还是确实没办法这样去实现,不得而知。
  4. 后续如果想做级联选择,就是改变on-change事件里的算法即可

http://lihuaxi.xjx100.cn/news/1430806.html

相关文章

taro h5列表拖拽排序 --- sortablejs 和 react-sortable-hoc

描述&#xff1a;列表&#xff0c;拖拽排序&#xff0c;只测试了h5 一、sortablejs 文档&#xff1a;http://www.sortablejs.com/ 1.安装sortablejs 2、引入 import Sortable from sortablejs3、页面 const [list, setList] useState([{id: item-1,content: 选项1 }, {id…

消息队列常见问题(1)-如何保障不丢消息

目录 1. 为什么消息队列会丢消息&#xff1f; 2. 怎么保障消息可靠传递&#xff1f; 2.1 生产者不丢消息 2.2 服务端不丢消息 2.3 消费者不丢消息 3. 消息丢失如何快速止损&#xff1f; 3.1 完善监控 3.2 完善止损工具 1. 为什么消息队列会丢消息&#xff1f; 现在主流…

springboot项目get请求下划线转驼峰@JsonProperty注解失效问题

问题&#xff1a;解决sprigboot项目get请求中有下划线的入参参数&#xff0c;如&#xff1a;first_name&#xff0c;希望在项目中将下划线格式转成firstName&#xff0c;用JsonProperty注解发现失效问题 1.核查&#xff1a;JsonProperty注解对应包是否正确 正确包&#xff1a…

k8s--使用cornJob定时执行sql文件

CronJob apiVersion: batch/v1beta1 kind: CronJob metadata:name: hello spec:schedule: "0 * * * *"jobTemplate:spec:template:spec:containers:- name: postgres-alpineimage: xxxximagePullPolicy: IfNotPresentcommand:- psql- -h- 数据库服务地址- -d- 数据库…

【PyQt5:Qtimer,QThread】创建计时器和线程,常用于信号与槽机制

文章目录 1、QTimer2、QThread 1、QTimer 计时器&#xff0c;timeout信号表示计时结束时&#xff0c;可以connect一个槽函数slot self.qtimer QTimer(self) self.qtimer.setSingleShot(True) # 设置计时器启动时只触发一次 self.qtimer.timeout.connect(slot) self.qtimer.s…

vue的axios进行ajax请求----ajax请求篇(三)

一、在vue框架中首先需要先安装依赖 npm install axios --save 二、在项目中的main.js中引用 import axios from axios;Vue.prototype.$axios axios&#xff1b; 三、在页面中进行使用 get 方式 axios({headers:{},url:“ ”, //urlparams:{},}).then(function(res){ …

(leecode)设计循环队列

&#xff08;温馨提示&#xff1a;这是博主最最喜欢的歌曲哦&#xff0c;没有之一&#xff09; 题目&#xff1a; 题解&#xff1a; 思路&#xff1a; 方法一(数组)&#xff1a; 方法二(链表)&#xff1a; 题目&#xff1a; 设计你的循环队列实现。 循环队列是一种线性数…

docker 部署 xxl-job-admin

1、先安装mysql docker pull mysql 2、运行mysql 容器 &#xff08; 端口 3306 容器名称 mysql 密码 123456 &#xff09; docker run -d --name mysql -e MYSQL_ROOT_PASSWORD123456 -p 3306:3306 mysql 3、将tables_xxl_job.sql文件&#xff08;官网地址&#xff1a;http…