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:'';
        width: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:'';
        width:20px;
        height: 20px;
        display: block;
        position:absolute;
        top:0px;
        left:-24px;
        z-index:999;
      }
      .el-checkbox__inner{
        top:0;
      }
  </style>

那么只點擊復選框時,由於上邊已說明的問題,還是無法實現需求,所以既然節點被點擊時可以實現選中對應的復選框並實現需求,那么就可以用節點的:before樣式來覆蓋在checkbox控件上,這樣就等於模擬了點擊復選框,就可以完美的實現需求想要的效果了!

需求有點復雜,也寫了這么多,並在文中伴有實操demo,相信各位童鞋都能看懂。

本文系原創,轉載請注明版權,謝謝!


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM