zoukankan      html  css  js  c++  java
  • vue+element-ui之tree树形控件有关子节点和父节点之间的各种选中关系详解

    做后端管理系统,永远是最蛋疼、最复杂也最欠揍的事情,也永远是前端开发人员最苦逼、最无奈也最尿性的时刻。蛋疼的是需求变幻无穷,如同二师兄的三十六般变化;复杂的是开发难度寸步难行,如同蜀道难,难于上青天;欠揍的是产品随心所欲、为所欲为,如同村霸横行乡里、只手遮天;苦逼的是前端苦不堪言,如同哑巴吃黄连,有苦说不出;无奈的是前端无可奈何花落去,如同至尊宝戴上金箍无法爱你,摘下金箍无法救你;尿性的是前端苦尽甘来,如同唐僧师徒历经九九八十一难,终成正果的高光时刻!

    又特么的南辕北辙了,矫情个鸟啊!有需求,上啊,很复杂,想啊,开发周期短,撸起袖子加油干啊(真特么的下流,一天到晚都是上啊,干啊,你特么泰迪啊)!好,闲话少叙,言归正传,咱们上一次讲到白眉大侠徐良...(你给我滚犊子)

    需求是这样的,有一个树形控件,默认所有节点都不选中。
    PS:如果贵司的需求没有那么复杂,就可以跳过以下内容,直接使用element-ui框架提供的tree树形控件及API即可。

    要求:

    1、选中父节点,子节点及孙子节点(甭管有多少层级,兹要是子辈节点)可以不选中,取消选中父节点,子节点及孙子节点也还是没有任何变化;

    2、选中子节点或孙子节点,必须选中父节点及祖父节点(甭管有多少层级,兹要是祖辈节点),取消选中子节点或孙子节点,父节点及祖父节点可以不取消选中;

    3、基于需求2,此时子节点及孙子节点和父节点、祖父节点都已选中,那么若取消选中父节点,则子节点及孙子节点必须取消选中,但父节点的父节点可以不取消选中,若取消选中祖父节点,则其下边的所有节点都要取消选中。

    看了需求,没有实操,是不是有点懵啊?第一次接到这样的需求且网上没有这样的解决方案,是不是无从下手啊?

    来看看实际的效果吧:https://runjs.cn/code/lu9nsctl

    看了效果,是不是恍然大悟?紧接着是不是就觉得既然在某种程度上父子节点没有关联关系,那还要这种树形控件干嘛?恭喜你,抓住重点了!

    首先,为什么我本人要用这种控件,因为我们的后台管理系统就是用的vue+element-ui框架,而且element-ui提供了这种树形控件的很多方法,比如选中子节点后要同时获取到该子节点的id以及其父节点和祖父节点的id,再比如通过接口返回的数据回显已经选中的所有节点,使用起来很方便的,只是需要熟悉它的API并灵活运用罢了。如果你没有用element-ui框架或者你想自己实现这样的效果,也未尝不可,只是在开发周期比较短的情况下,你要自己去写html、js、css,暂且不说js实现起来有多费劲,单说html和css就够你喝一壶的。当然,我也不是说不提倡自己去写,在时间允许的情况下自己写也可以,自己实现出来的,很能提高自己的js能力和业务逻辑的!

    接下来就是具体的实现代码了,这篇文章的解决方案是基于vue+element-ui的。

    <!DOCTYPE html>
    <html>
      <head>
    	<meta charset="UTF-8">
    	<script src="https://cdn.staticfile.org/vue/2.2.2/vue.min.js"></script>
    	<script src="https://unpkg.com/element-ui/lib/index.js"></script>
    	<link rel="stylesheet" href="https://unpkg.com/element-ui/lib/theme-chalk/index.css">
      <style>
        .el-tree-node__label{
            position: relative;
          }
          .el-tree-node__label:before{
            content:'';
            20px;
            height: 20px;
            display: block;
            position:absolute;
            top:0px;
            left:-24px;
            z-index:999;
          }
          .el-checkbox__inner{
            top:0;
          }
      </style>
    	<title>element-ui树形控件</title>
      </head>
    <body>
    	<div id="app">
          <el-tree
    	    :data="treeData"
    	    show-checkbox
    	    node-key="id"
    	    check-on-click-node
    	    :default-expand-all="true"
    	    :check-strictly="true"
    	    :expand-on-click-node="false"
    	    @node-click="nodeClick"
          >
    	  </el-tree>
    	</div>
      <script>
      let vm = new Vue({
        el: '#app',
        data: {
          treeData: [{
            id: 1,
            label: '一级 1',
            children: [{
              id: 4,
              label: '二级 1-1',
              children: [{
                id: 9,
                label: '三级 1-1-1',
                children: [{
                  id: 11,
                  label: '四级 1-1-1',
                }]
              }, {
                id: 10,
                label: '三级 1-1-2'
              }]
            }]
          }, {
            id: 2,
            label: '一级 2',
            children: [{
              id: 5,
              label: '二级 2-1'
            }, {
              id: 6,
              label: '二级 2-2'
            }]
          }, {
            id: 3,
            label: '一级 3',
            children: [{
              id: 7,
              label: '二级 3-1'
            }, {
              id: 8,
              label: '二级 3-2'
            }]
          }]
        },
        methods: {
          nodeClick(data, node){    
            vm.childNodesChange(node);
            vm.parentNodesChange(node);
          },
          childNodesChange(node){
            let len = node.childNodes.length;
            for(let i = 0; i < len; i++){
              node.childNodes[i].checked = false;
              vm.childNodesChange(node.childNodes[i]);
            }   
          },
          parentNodesChange(node){
            if(node.parent){
              for(let key in node){
                if(key == "parent"){
                  node[key].checked = true;
                  vm.parentNodesChange(node[key]);
                }
              }
            }      
          }
        }
      })
    </script>
    </body>
    </html>
    

    注意:
    1、关于代码中element-ui树形控件的API可自行查阅官方文档,这里不做赘述;

    2、控件中使用了check-on-click-node这个属性,官方文档的解释是:是否在点击节点的时候选中节点,默认值为 false,即只有在点击复选框时才会选中节点。为什么要使用这个属性呢?

    因为在点击复选框时,虽然官方文档给了一个check的方法,解释是:当复选框被点击的时候触发,其有两个参数,依次为:传递给 data 属性的数组中该节点所对应的对象、树目前的选中状态对象,包含 checkedNodes、checkedKeys、halfCheckedNodes、halfCheckedKeys 四个属性,但依旧无法实现我想要的效果。

    这三张图就是check方法打印出来的效果,打印出来的参数的属性中根本就没有可供设置为true或false的checked,更不包含父节点,这怎么玩?还怎么设置父节点?

    好在控件有node-click这个方法,官方解释是:节点被点击时的回调,其有三个参数,依次为:传递给 data 属性的数组中该节点所对应的对象、节点对应的 Node、节点组件本身。正好这个方法的第二个参数Node就是我想要的,因为既然某种程度上父子节点无关联,那么要想获得当前节点的父节点和子节点,就只能通过第二个参数Node去获取了。这里具体的参数的打印效果我就不展示了。

    其实这里还有一个问题,就是如果没有下边的样式:

    <style>
        .el-tree-node__label{
            position: relative;
          }
          .el-tree-node__label:before{
            content:'';
            20px;
            height: 20px;
            display: block;
            position:absolute;
            top:0px;
            left:-24px;
            z-index:999;
          }
          .el-checkbox__inner{
            top:0;
          }
      </style>
    

    那么只点击复选框时,由于上边已说明的问题,还是无法实现需求,所以既然节点被点击时可以实现选中对应的复选框并实现需求,那么就可以用节点的:before样式来覆盖在checkbox控件上,这样就等于模拟了点击复选框,就可以完美的实现需求想要的效果了!

    需求有点复杂,也写了这么多,并在文中伴有实操demo,相信各位童鞋都能看懂。

    本文系原创,转载请注明版权,谢谢!

  • 相关阅读:
    设计一个数据结构,包含两个函数,1.插入一个数字,2.获得中数
    数状数组
    25匹马,每次能5匹一起跑,选出最快的3匹
    禁止ImageCapture自动启动
    SublimeText Videos Notes
    10G个64bit整数,找出中位数
    python初步要点II
    python初步要点
    找出丢失的数字
    nice & renice
  • 原文地址:https://www.cnblogs.com/tnnyang/p/10365545.html
Copyright © 2011-2022 走看看