vue實現(xiàn)的樹形結(jié)構(gòu)加多選框示例
本文實例講述了vue實現(xiàn)的樹形結(jié)構(gòu)加多選框。分享給大家供大家參考,具體如下:
前面說了如何用遞歸組件來寫vue樹形結(jié)構(gòu),寫了樹形結(jié)構(gòu)還要在前面加多選框,然后往數(shù)組里push選項,并在左邊顯示出來,然后左邊進行拖拽排序,拖拽排序上一篇文章我已經(jīng)介紹過了,在這我就不介紹了,如何用阿里巴巴矢量圖標庫我也有相關(guān)文章,也不介紹了,本節(jié)主要介紹vue樹形結(jié)構(gòu)加多選框,并實現(xiàn)一定的邏輯,比如全選,單選,全選和單選之間的聯(lián)動
先看下目錄結(jié)構(gòu)
下面我直接貼下代碼
首先是pages文件夾中tree.vue頁面中引用組件
下面是tree.vue的代碼
<template> <div class = "loginModuel"> <Tree :menus = "menus" :depth = "depth" @selectItem = "selectItem" :actId = "actId" @checkItem = "checkItem"></Tree> </div> </template> <script src = "./index.js"></script> <style lang = "scss" scoped src = "./index.scss"></style>
然后是tree.vue引入的index.js的代碼
import Tree from '../../components/tree/tree'; import axios from 'axios'; export default{ data(){ return{ msg:"這是登錄頁面", depth:0, menus:[], actId:"", } }, components:{ Tree }, methods:{ //用ajax獲取數(shù)據(jù) getData(){ return axios.get('/static/json/data.json'); }, // 調(diào)用ajax函數(shù) async getTree(){ var last = await this.getData(); if(last.data.code == 1){ this.menus = last.data.data; //在每一項中添加selectArr和show this.addShow(this.menus); } }, //遞歸函數(shù)在每一項中添加selectArr和show addShow(arr){ for(var i = 0; i < arr.length;i++){ this.$set(arr[i],"show",true); this.$set(arr[i],"selectArr",[]); if(arr[i].userList && arr[i].userList.length > 0){ this.addShow(arr[i].userList) } } }, //點擊箭頭使樹展開收縮 selectItem(data){ if(data.userList && data.userList.length > 0){ //如果此項下有userList且length大于0,則切換展開與折疊狀態(tài) data.show = !data.show; }else{ //如果此項下沒有userList或length等于0,則將選中的id賦值給actId this.actId = data.id; } }, //進行多選勾選 checkItem(data){ if(data.selectArr.length > 0){ //如果這一項的selectArr有值,說明是被勾選狀態(tài),要把selectArr清空,清空勾選 data.selectArr = []; //如果此選項清空勾選后,如果下面有userList的話,那么也同時要清空 if(data.userList && data.userList.length > 0){ this.clearChild(data.userList); } //如果此選項清空勾選后,要把所有的父元素,也全部清空勾選,因為它不勾選了,所有父元素的狀態(tài)不可能還處于勾選狀態(tài),不管它勾選不勾選,我們都要清除一遍,以防萬一 this.clearFather(this.menus,data); }else{//如果這一項的selectArr為[],說明是未被勾選狀態(tài),在selectArr里加id值,添加勾選 data.selectArr.push(data.id); //如果此選項清空勾選后,如果下面有userList的話,那么也同時勾選下面所有的孩子 if(data.userList && data.userList.length > 0){ this.addChild(data.userList); } //如果此選項勾選后,要判斷所有的上級元素是不是應(yīng)該全部打勾 this.selectFather(this.menus,data); } }, //定義函數(shù)清空所有孩子的勾選 clearChild(arr){ for(var i = 0; i < arr.length;i++){ arr[i].selectArr = []; if(arr[i].userList && arr[i].userList.length > 0){ this.clearChild(arr[i].userList); } } }, //定義函數(shù)添加所有孩子的勾選 addChild(arr){ for(var i = 0; i < arr.length;i++){ arr[i].selectArr.push(arr[i].id); if(arr[i].userList && arr[i].userList.length > 0){ this.addChild(arr[i].userList); } } }, //定義函數(shù)一層一層的往上尋找父元素的userList clearFather(father,data){ for(var i = 0; i < father.length;i++){ if(father[i].id == data.id){ //找到data所在的userList為father,然后再通過這個userList找到擁有這個userList的父元素 this.clearRealFather(this.menus,father); }else if(father[i].userList && father[i].userList.length > 0){ this.clearFather(father[i].userList,data); } } }, //定義函數(shù)根據(jù)找到的上層父元素的userList來尋找父元素,并將他們清除勾選 clearRealFather(menus,arr){ for(var i = 0; i < menus.length;i++){ if(menus[i].userList == arr){ //找到這個擁有userList的父元素后,將此selectArr清空 menus[i].selectArr = []; //找到這個擁有userList的父元素后,再調(diào)用clearFather,再進行向上尋找父元素,知道沒有父元素為止 this.clearFather(this.menus,menus[i]); }else if(menus[i].userList && menus[i].userList.length > 0){ this.clearRealFather(menus[i].userList,arr); } } }, //定義函數(shù)一層一層的往上尋找父元素的userList selectFather(father,data){ for(var i = 0; i < father.length;i++){ if(father[i].id == data.id){ var arr = []; for(var j = 0; j < father.length;j++){ if(father[j].selectArr.length > 0){ arr.push(father[i]); } } //判斷此數(shù)組中是不是所有的selectArr都有值,如果有值,就執(zhí)行selectRealFather,將上層父元素也勾選 if(arr.length == father.length){ this.selectRealFather(this.menus,father); } }else if(father[i].userList && father[i].userList.length > 0){ this.selectFather(father[i].userList,data); } } }, //定義函數(shù)根據(jù)找到的上層父元素的userList來尋找父元素,并將他們清除勾選 selectRealFather(menus,arr){ for(var i = 0; i < menus.length;i++){ if(menus[i].userList == arr){ //找到這個擁有userList的父元素后,給selectArr賦值,使其勾選 menus[i].selectArr.push(menus[i].id); //找到這個擁有userList的父元素后,再調(diào)用clearFather,再進行向上尋找父元素,知道沒有父元素為止 this.clearFather(this.menus,menus[i]); }else if(menus[i].userList && menus[i].userList.length > 0){ this.selectRealFather(menus[i].userList,arr); } } } }, mounted(){ this.getTree(); } }
然后是樹形組件components文件夾中tree.vue的代碼
1.tree.vue
<template> <ul class = "treeMoudel"> <li v-for = "(item,index) in menus" :key = "index"> <!-- 遍歷menus,如果傳過來的depth等于0,就添加topNode的class,如果不等于0,就添加noTopNode的class --> <div :class = "{'itemTree':true,'topNode':depth == 0,'noTopNode':depth != 0,'active':actId == item.id}"> <!-- 判斷如果含有name字段就顯示name字段 --> <span :style = "transform" v-if = "item.name" :class = "{'topSpan':depth == 0,'noTopSpan':depth != 0}"> <!-- 如果item有孩子且item.show為false,那么圖標為折疊圖標 --> <i class = "el-icon-caret-right" v-if = "item.userList && item.userList.length > 0 && !item.show" @click = "selectItem(item)"></i> <!-- 如果item有孩子且item.show為true,那么圖標為展開圖標 --> <i class = "el-icon-caret-bottom" v-if = "item.userList && item.userList.length > 0 && item.show" @click = "selectItem(item)"></i> <i class = "selectBox" @click = "checkItem(item)"> <!-- 如果item的selectArr.length是大于0的,也就是里面有值的話就是勾選狀態(tài),否則就是不勾選狀態(tài) --> <i :class = "{'checkName iconfont':true, 'gouxuan5':item.selectArr.length > 0}" ></i> </i> {{item.name}} </span> <!-- 判斷如果含有username字段就顯示username字段 --> <span :style = "transform" v-if = "item.username" :class = "{'topSpan':depth == 0,'noTopSpan':depth != 0}"> <!-- 如果item有孩子且item.show為false,那么圖標為折疊圖標 --> <i class = "el-icon-caret-right" v-if = "item.userList && item.userList.length > 0 && !item.show" @click = "selectItem(item)"></i> <!-- 如果item有孩子且item.show為true,那么圖標為展開圖標 --> <i class = "el-icon-caret-bottom" v-if = "item.userList && item.userList.length > 0 && item.show" @click = "selectItem(item)"></i> <i class = "selectBox" @click = "checkItem(item)"> <!-- 如果item的selectArr.length是大于0的,也就是里面有值的話就是勾選狀態(tài),否則就是不勾選狀態(tài) --> <i :class = "{'checkUsername iconfont':true, 'gouxuan5':item.selectArr.length > 0}"></i> </i> {{item.username}} </span> </div> <el-collapse-transition> <!-- 遞歸組件就是自己調(diào)用自己,這里是在自己的組件內(nèi)再次調(diào)用自己,但是務(wù)必要和pages中的tree頁面中使用的一模一樣才可以,否則樹不會生效 --> <Tree v-if = "item.userList && item.userList.length > 0 && item.show" :menus = "item.userList" :depth = "depth+4" @selectItem = "selectItem" :actId = "actId" @checkItem = "checkItem"></Tree> </el-collapse-transition> </li> </ul> </template> <script src = "./index.js"></script> <style src = "./index.scss" lang = "scss" scoped></style>
2.tree.vue中引入的index.js
export default{ name:"Tree", props:["menus","depth","actId"], data(){ return{ msg:"這是二級菜單樹", } }, methods:{ // 將selectItem方法暴露出去 selectItem(item){ this.$emit("selectItem",item); }, // 將checkItem方法暴露出去 checkItem(item){ this.$emit("checkItem",item); } }, computed:{ //通過傳過來的depth計算下級目錄的偏移量,這里我用的transform transform(){ return 'transform:translateX(' + this.depth*10 + 'px)'; } } }
3.tree.vue中引入的index.scss
.treeMoudel{ li{ .itemTree{ width: 100%; padding-left:30px; position: relative; &:hover{ background:#2B9EEE; color:#fff; } .selectBox{ display: inline-block; width: 16px; height:16px; border:1px solid #ccc; border-radius: 3px; position: relative; background: #fff; top:2px; .checkName{ position: absolute; top:-16px; left:0px; color:#333; } .checkUsername{ position: absolute; top:-12px; left:0px; color:#333; } } span{ display: inline-block; position: absolute; font-size:14px; } .topSpan{ font-size:16px; } .noTopSpan{ font-size:14px; } } .topNode{ height:55px; line-height: 55px; font-size:16px; cursor: pointer; } .active{ background:#2B9EEE; color:#fff; } .noTopNode{ height:45px; line-height:45px; &:hover{ background:#2B9EEE; cursor: pointer; color:#fff; } } } }
看一下模擬數(shù)據(jù)的data.json長什么樣子吧
{ "code":1, "data":[ { "id":"1.2", "name":"技術(shù)部", "userList":[ { "id":"788d", "username":"html", "role":"主管" }, { "id":"sda", "username":"vue", "role":"普通" } ] }, { "id":"1.3", "name":"策劃部", "userList":[ { "id":"dsf", "username":"jack", "role":"主管" }, { "id":"asdf", "username":"rose", "role":"普通" } ] } ] }
至此,一個樹形組件加多選框就做好了
下面看下效果圖
ok,自此這一功能就實現(xiàn)啦,代碼講解我就不寫了,注釋里寫的清清楚楚的,看注釋就好啦!
希望本文所述對大家vue.js程序設(shè)計有所幫助。
相關(guān)文章
vue+iview 兼容IE11瀏覽器的實現(xiàn)方法
這篇文章主要介紹了vue+iview 兼容IE11瀏覽器的實現(xiàn)方法,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2019-01-01基于Vue3和element-plus實現(xiàn)登錄功能(最終完整版)
這篇文章主要介紹了基于Vue3和element-plus實現(xiàn)一個完整的登錄功能,本文結(jié)合示例代碼給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下2023-03-03nuxt.js中間件實現(xiàn)攔截權(quán)限判斷的方法
這篇文章主要介紹了nuxt.js中間件實現(xiàn)攔截權(quán)限判斷的方法,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2018-11-11使用vue3+ts+setup獲取全局變量getCurrentInstance的方法實例
這篇文章主要給大家介紹了關(guān)于使用vue3+ts+setup獲取全局變量getCurrentInstance的相關(guān)資料,文中通過實例代碼介紹的非常詳細,對大家學習或者使用vue3具有一定的參考學習價值,需要的朋友可以參考下2022-08-08