vue遞歸實現(xiàn)樹形組件
本文實例為大家分享了vue遞歸實現(xiàn)樹形組件的具體代碼,供大家參考,具體內(nèi)容如下
1. 先來看一下效果:
2. 代碼部分 (myTree.vue)
圖片可以自己引一下自己的圖片,或者使用iconfont的css引入。
<template> ? ? <div class="tree"> ? ? ? ? <ul class="ul"> ? ? ? ? ? ? <li v-for="(item,index) of treeMenu" :key="index"> ? ? ? ? ? ? ? ? <div class="jiantou" @click="changeStatus(index)"> ? ? ? ? ? ? ? ? ? ? <img src="../../assets/right.png" v-if="!scopesDefault[index]===true && item.children"> ? ? ? ? ? ? ? ? ? ? <img src="../../assets/down.png" v-if="scopesDefault[index]===true && item.children "> ? ? ? ? ? ? ? ? </div> ? ? ? ? ? ? ? ? <input type="checkbox" @click="checkBox(item)" v-model="item.check"> ? ? ? ? ? ? ? ? <span @click="changeStatus(index)">{{item.label}}</span> ? ? ? ? ? ? ? ? <div class="subtree"> ? ? ? ? ? ? ? ? ? ? <tree-menu :treeMenu='item.children' v-if="scopesDefault[index]" @selectnode = "selectnode"></tree-menu> ? ? ? ? ? ? ? ? </div> ? ? ? ? ? ? </li> ? ? ? ? ? </ul>? ? ? </div>? </template> <script> ?? ?export default{ ? ? name:'treeMenu', ? ? ?props:{ ? ? ? ? treeMenu:{ ? ? ? ? ? ? type:Array, ? ? ? ? ? ? default:[] ? ? ? ? }, ? ? }, ? ? data(){ ? ? ? ? return{ ? ? ? ? ? ? scopesDefault: [], ? ? ? ? ? ? scopes: [],? ? ? ? ? ? ? node:[], ? ? ? ? ? ? flatTreeMenu:[], ? ? ? ? ? ? check:'', ? ? ? ? } ? ? }, ? ? methods:{ ? ? ? ? //展開 ? ? ? ? scope() { ? ? ? ? ? ? this.treeMenu.forEach((item, index) => { ? ? ? ? ? ? ? ? this.scopesDefault[index] = false ? ? ? ? ? ? ? ? if ('children' in item) { ? ? ? ? ? ? ? ? ? ? this.scopes[index] = true ? ? ? ? ? ? ? ? ? ? //console.log(item, index) ? ? ? ? ? ? ? ? } else { ? ? ? ? ? ? ? ? ? ? this.scopes[index] = false ? ? ? ? ? ? ? ? } ? ? ? ? ? ? }) ? ? ? ? }, ? ? ? ? changeStatus(index) { ? ? ? ? ? ? if (this.scopesDefault[index] == true) { ? ? ? ? ? ? ? ? this.$set(this.scopesDefault, index, false) ? ? ? ? ? ? } else { ? ? ? ? ? ? ? ? this.$set(this.scopesDefault, index, this.scopes[index]) ? ? ? ? ? ? } ? ? ? ? }, ? ? ? ? //nodelist 深度優(yōu)先遞歸 ? ? ? ? checkBox(node,nodelist=[]){ ? ? ? ? ? ? //console.log("start:",node,nodelist) ? ? ? ? ? ? if(node!==null){ ? ? ? ? ? ? ? ? nodelist.push(node); ? ? ? ? ? ? ? ? if(node.children){ ? ? ? ? ? ? ? ? ? ? let children=node.children; ? ? ? ? ? ? ? ? ? ? for(let i=0;i<children.length;i++){ ? ? ? ? ? ? ? ? ? ? ? ? this.checkBox(children[i],nodelist)//遞歸調(diào)用 ? ? ? ? ? ? ? ? ? ? ? ? children[i].check = nodelist[0].check==false?true:false;//選中父節(jié)點,子節(jié)點全選,取消,子節(jié)點取消 ? ? ? ? ? ? ? ? ? ? } ? ? ? ? ? ? ? ? } ? ? ? ? ? ? } ? ? ? ? ? ? this.node=node; ? ? ? ? ? ? this.check=node.check ? ? ? ? }, ? ? ? ? selectnode(node){ ? ? ? ? ? ? this.$emit("selectnode",node); ? ? ? ? } ? ? }, ? ? watch:{? ? ? ? ? node:{ ? ? ? ? ? ? handler(val){ ? ? ? ? ? ? ? ? this.selectnode(val); ? ? ? ? ? ? }, ? ? ? ? ? ? immediate: true ? ? ? ? }, ? ? ? ? check:{ ? ? ? ? ? ? handler(val){ ? ? ? ? ? ? ? ? this.selectnode(this.node); ? ? ? ? ? ? }, ? ? ? ? ? ? immediate: true ? ? ? ? } ? ? }, ? ? mounted(){ ? ? ? ? this.scope();? ? ? } } </script>
<style lang = "scss" scoped> .tree{ ? ? .ul{ ? ? ? ? margin: 5px 0 5px 0; ? ? ? ? >li{ ? ? ? ? ? ? .jiantou{ ? ? ? ? ? ? ? ? display: inline-block; ? ? ? ? ? ? ? ? width: 15px; ? ? ? ? ? ? ? ? >img{ ? ? ? ? ? ? ? ? position: relative; ? ? ? ? ? ? ? ? top: 2.0px; ? ? ? ? ? ? ? ? left: 4px; ? ? ? ? ? ? ? ? } ? ? ? ? ? ? } ? ? ? ? ? ? .subtree{ ? ? ? ? ? ? ? ? margin-left: 20px; ? ? ? ? ? ? ? ? margin-top: 8px; ? ? ? ? ? ? ? ? margin-bottom: 8px; ? ? ? ? ? ? } ? ? ? ? } ? ? } } input[type=checkbox]{ ? ? visibility: hidden; ? ? cursor: pointer; ? ? position: relative; ? ? width: 15px; ? ? height: 15px; ? ? font-size: 14px; ? ? border: 1px solid #dcdfe6; ? ? background-color: #fff !important; ? ? &::after{ ? ? ? ? position: absolute; ? ? ? ? top: 0; ? ? ? ? background-color: #fff; ? ? ? ? border: 1px solid #ddd; ? ? ? ? color: #000; ? ? ? ? width: 15px; ? ? ? ? height: 15px; ? ? ? ? display: inline-block; ? ? ? ? visibility: visible; ? ? ? ? padding-left: 0px; ? ? ? ? text-align: center; ? ? ? ? content: ' '; ? ? ? ? border-radius: 3px; ? ? ? ? transition: all linear .1s; ? ? } ? ? &:checked::after{ ? ? ? ? content: "\2713"; ? ? ? ? font-size: 12px; ? ? ? ? background-color: #409eff; ? ? ? ? border: 1px solid #409eff; ? ? ? ? transition: all linear .1s; ? ? ? ? color: #fff; ? ? ? ? font-weight: bold; ? ? } } .check{ ? ? &:checked::after{ ? ? ? ? content: "--" !important; ? ? } } </style>
講解:
1、調(diào)用組件:
我這用來一個global.js
來控制組件的使用(這個js附在文章末尾了),在component
文件夾中建立一個myTree
文件夾,里面放同名vue文件(myTree.vue
),這樣無論在哪里調(diào)用這個組件,都可以直接使用<my-tree></my-tree>
的方式去調(diào)用。
2、組件的方法:
scope():
會生成一個數(shù)組,里面有根節(jié)點是否有子節(jié)點,如本代碼里設定的數(shù)據(jù),會有scopes=[true,true,true]
這樣的結果。changeStatus():
每點擊標題或者箭頭,如果當前下標的節(jié)點有沒有子節(jié)點,再將結果動態(tài)賦值給scopesDefault[index]
,將這個值放于dom上控制開關,遞歸組件。checkBox():
在組件內(nèi)部實現(xiàn)了點擊全選、點擊取消全選的功能,遞歸調(diào)用當前方法,將子元素的狀態(tài)隨父元素一起變化。selectnode():
將當前點擊的node的節(jié)點內(nèi)容上傳到父組件。
3、監(jiān)聽:
同時監(jiān)聽:不同節(jié)點的切換、同一個節(jié)點的是否選中的切換,監(jiān)聽得到的結果都傳到父組件中。
4、組件遞歸:調(diào)用時與父組件相同
3. 使用組件(useMyTree.vue)
<template> ? ? <div class = "loginModuel"> ? ? ? ? <my-tree :treeMenu='tree' @selectnode="selectnode"></my-tree> ? ? </div> </template> <script> export default{ ? ? data(){ ? ? ? ? return{ ? ? ? ? ? ? msg:"這是登錄頁面", ? ? ? ? ? ? tree:[ ? ? ? ? ? ? ? ? ? { ? ? ? ? ? ? ? ? ? ? id:1, ? ? ? ? ? ? ? ? ? ? label:"1級目錄1", ? ? ? ? ? ? ? ? ? ? check:false, ? ? ? ? ? ? ? ? ? ? children:[ ? ? ? ? ? ? ? ? ? ? ? ? { ? ? ? ? ? ? ? ? ? ? ? ? ? ? id:"1-1", ? ? ? ? ? ? ? ? ? ? ? ? ? ? pid:1, ? ? ? ? ? ? ? ? ? ? ? ? ? ? label:"1.1目錄", ? ? ? ? ? ? ? ? ? ? ? ? ? ? check:false ? ? ? ? ? ? ? ? ? ? ? ? }, ? ? ? ? ? ? ? ? ? ? ? ? { ? ? ? ? ? ? ? ? ? ? ? ? ? ? id:"1-2", ? ? ? ? ? ? ? ? ? ? ? ? ? ? pid:1, ? ? ? ? ? ? ? ? ? ? ? ? ? ? label:"1.2目錄", ? ? ? ? ? ? ? ? ? ? ? ? ? ? check:false ? ? ? ? ? ? ? ? ? ? ? ? }, ? ? ? ? ? ? ? ? ? ? ? ? { ? ? ? ? ? ? ? ? ? ? ? ? ? ? id:"1-3", ? ? ? ? ? ? ? ? ? ? ? ? ? ? pid:1, ? ? ? ? ? ? ? ? ? ? ? ? ? ? label:"1.3目錄", ? ? ? ? ? ? ? ? ? ? ? ? ? ? check:false ? ? ? ? ? ? ? ? ? ? ? ? }, ? ? ? ? ? ? ? ? ? ? ] ? ? ? ? ? ? ? ? }, ? ? ? ? ? ? ? ? { ? ? ? ? ? ? ? ? ? id:2, ? ? ? ? ? ? ? ? ? label:"1級目錄2", ? ? ? ? ? ? ? ? ? check:false, ? ? ? ? ? ? ? ? ? children:[ ? ? ? ? ? ? ? ? ? ? ? { ? ? ? ? ? ? ? ? ? ? ? ? ? id:"2-1", ? ? ? ? ? ? ? ? ? ? ? ? ? label:"2.1目錄", ? ? ? ? ? ? ? ? ? ? ? ? ? check:false, ? ? ? ? ? ? ? ? ? ? ? ? ? pid:2, ? ? ? ? ? ? ? ? ? ? ? ? ? children:[ ? ? ? ? ? ? ? ? ? ? ? ? ? ? { ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? id:"2-1-1", ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? pid:'2-1', ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? label:"2.1.1目錄", ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? check:false, ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? children:[ ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? { ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? id:"2-1-1-1", ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? pid:'2-1-1', ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? label:"2.1.1.1目錄", ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? check:false, ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? children:[ ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? { ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? id:"2-1-1-1-1", ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? pid:'2-1-1-1', ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? label:"2.1.1.1.1目錄", ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? check:false, ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? }, ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? { ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? id:"2-1-1-1-2", ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? pid:'2-1-1-1', ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? label:"2.1.1.1.2目錄", ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? check:false, ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? }, ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ] ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? }, ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ] ? ? ? ? ? ? ? ? ? ? ? ? ? ? }, ? ? ? ? ? ? ? ? ? ? ? ? ? ? { ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? id:"2-1-2", ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? pid:'2-1', ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? label:"2.1.2目錄", ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? check:false, ? ? ? ? ? ? ? ? ? ? ? ? ? ? }, ? ? ? ? ? ? ? ? ? ? ? ? ? ? { ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? id:"2-1-3", ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? pid:'2-1', ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? label:"2.1.3目錄", ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? check:false, ? ? ? ? ? ? ? ? ? ? ? ? ? ? }, ? ? ? ? ? ? ? ? ? ? ? ? ] ? ? ? ? ? ? ? ? ? ? ? }, ? ? ? ? ? ? ? ? ? ? ? { ? ? ? ? ? ? ? ? ? ? ? ? ? id:"2-2", ? ? ? ? ? ? ? ? ? ? ? ? ? pid:2, ? ? ? ? ? ? ? ? ? ? ? ? ? label:"2.2目錄", ? ? ? ? ? ? ? ? ? ? ? ? ? check:false ? ? ? ? ? ? ? ? ? ? ? } ? ? ? ? ? ? ? ? ? ] ? ? ? ? ? ? ? },//在此繼續(xù)添加目錄 ? ? ? ? ? ? ? { ? ? ? ? ? ? ? ? id:3, ? ? ? ? ? ? ? ? label:"1級目錄3", ? ? ? ? ? ? ? ? check:false, ? ? ? ? ? ? ? ? children:[ ? ? ? ? ? ? ? ? ? ? { ? ? ? ? ? ? ? ? ? ? ? ? id:"3-1", ? ? ? ? ? ? ? ? ? ? ? ? pid:3, ? ? ? ? ? ? ? ? ? ? ? ? label:"3.1目錄", ? ? ? ? ? ? ? ? ? ? ? ? check:false, ? ? ? ? ? ? ? ? ? ? ? ? children:[ ? ? ? ? ? ? ? ? ? ? ? ? ? ? { ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? id:"3-1-1", ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? pid:"3-1", ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? label:"3.1.1目錄", ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? check:false, ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? children:[ ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? { ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? id:"3-1-1-1", ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? pid:"3-1-1", ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? label:"3.1.1.1目錄", ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? check:false, ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? children:[ ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? { ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? id:"3-1-1-1-1", ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? pid:"3-1-1-1", ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? label:"3.1.1.1.1目錄", ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? check:false ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? }, ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ] ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? }, ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ] ? ? ? ? ? ? ? ? ? ? ? ? ? ? }, ? ? ? ? ? ? ? ? ? ? ? ? ] ? ? ? ? ? ? ? ? ? ? } ? ? ? ? ? ? ? ? ] ? ? ? ? ? ? }, ? ? ? ? ? ? ], ? ? ? ? ? ? plist:[],//此級以上所有父節(jié)點列表 ? ? ? ? ? ? flatTree:[],//tree的平行數(shù)據(jù) ? ? ? ? ? ? node:'',//當前點擊的node, ? ? ? ? } ? ? }, ? ? methods:{ ? ? ? ? //將tree樹形數(shù)據(jù)轉(zhuǎn)換為平行數(shù)據(jù) ? ? ? ? transformData(tree){ ? ? ? ? ? ? tree.forEach(item=>{ ? ? ? ? ? ? ? ? this.flatTree.push(item); ? ? ? ? ? ? ? ? item.children && item.children.length>0 ? this.transformData(item.children) : "" ? ? ? ? ? ? }) ? ? ? ? }, ? ? ? ? //子組件傳遞過來的點擊的node的值 ? ? ? ? selectnode(node){ ? ? ? ? ? ? this.node=node; ? ? ? ? ? ? this.flatTree=[]; ? ? ? ? ? ? this.transformData(this.tree); ? ? ? ? ? ? if(node.check==false){//這個節(jié)點已經(jīng)被選中,正在點擊取消選中 ? ? ? ? ? ? ? ? this.plist=[];//每次點擊一個新的節(jié)點都將原來plist的內(nèi)容清空 ? ? ? ? ? ? ? ? this.getParentnode(this.flatTree,node.pid) ? ? ? ? ? ? }else{//正在選中 ? ? ? ? ? ? ? ? this.childAllToParent(node,this.flatTree,1); ? ? ? ? ? ? } ? ? ? ? }, ? ? ? ? //子節(jié)點取消選中,拿到此子節(jié)點所有的父節(jié)點plist ? ? ? ? getParentnode(tree,pid){ ? ? ? ? ? ? //this.plist=[] ? ? ? ? ? ? if(pid!==null){ ? ? ? ? ? ? ? ? tree.forEach(item=>{ ? ? ? ? ? ? ? ? ? ? if(item.id==pid){ ? ? ? ? ? ? ? ? ? ? ? ? this.plist.push(item) ? ? ? ? ? ? ? ? ? ? ? ? this.getParentnode(this.flatTree,item.pid) ? ? ? ? ? ? ? ? ? ? } ? ? ? ? ? ? ? ? }) ? ? ? ? ? ? }? ? ? ? ? ? ? if(!pid){ ? ? ? ? ? ? ? ? this.plist.forEach(item=>{ ? ? ? ? ? ? ? ? ? ? this.updateParentCheck(this.tree,item) ? ? ? ? ? ? ? ? }) ? ? ? ? ? ? } ? ? ? ? }, ? ? ? ? //將原數(shù)據(jù)tree對應id的項的check值改為false ? ? ? ? updateParentCheck(tree,plistItem){ ? ? ? ? ? ? //console.log("方法updateParentCheck接收的plistItem參數(shù):",plistItem) ? ? ? ? ? ? tree.forEach(item=>{ ? ? ? ? ? ? ? ? if(item.id==plistItem.id){ ? ? ? ? ? ? ? ? ? ? item.check=false; ? ? ? ? ? ? ? ? } ? ? ? ? ? ? ? ? if(item.id!==plistItem.id && item.children){ ? ? ? ? ? ? ? ? ? ? this.updateParentCheck(item.children,plistItem) ? ? ? ? ? ? ? ? } ? ? ? ? ? ? }) ? ? ? ? }, ? ? ? ? //子節(jié)點全部選中后父節(jié)點選中 ? ? ? ? childAllToParent(node,flatTree,j){ ? ? ? ? ? ? let fatherNode=''; ? ? ? ? ? ? let brotherNode=[]; ? ? ? ? ? ? this.flatTree.forEach(item=>{ ? ? ? ? ? ? ? ? if(node.pid && node.pid==item.id){ ? ? ? ? ? ? ? ? ? ? fatherNode=item;//找到了父節(jié)點--用于改變check的值 ? ? ? ? ? ? ? ? } ? ? ? ? ? ? }) ? ? ? ? ? ? //判斷該結點所有的兄弟節(jié)點是否全部選中 ? ? ? ? ? ? flatTree.forEach(item=>{ ? ? ? ? ? ? ? ? if(item.pid && node.pid && item.pid==node.pid){ ? ? ? ? ? ? ? ? ? ? brotherNode.push(item)//找到所有的兄弟節(jié)點 ? ? ? ? ? ? ? ? } ? ? ? ? ? ? }) ? ? ? ? ? ? //i為被選中的兄弟節(jié)點的個數(shù) ? ? ? ? ? ? let i=0; ? ? ? ? ? ? this.flatTree.forEach(item=>{ ? ? ? ? ? ? ? ? if(node.pid==item.pid && item.check==true){ ? ? ? ? ? ? ? ? ? ? i=i+1; ? ? ? ? ? ? ? ? } ? ? ? ? ? ? }) ? ? ? ? ? ? //修改父節(jié)點的選中值 ? ? ? ? ? ? if(i==brotherNode.length && fatherNode){ ? ? ? ? ? ? ? ? fatherNode.check=true ? ? ? ? ? ? } ? ? ? ? ? ? // console.log(`第j次遞歸 j=${j}`) ? ? ? ? ? ? // console.log(`選中的bro=${i},brother的個數(shù):${brotherNode.length}`) ? ? ? ? ? ? // console.log("父節(jié)點:",fatherNode,"兄弟節(jié)點",brotherNode) ? ? ? ? ? ? if(fatherNode.pid!==undefined){ ? ? ? ? ? ? ? ? j=j+1; ? ? ? ? ? ? ? ? this.childAllToParent(fatherNode,this.flatTree,j) ? ? ? ? ? ? } ? ? ? ? } ? ? }, ? ? mounted(){ ? ? ? ? this.transformData(this.tree);//數(shù)據(jù)初始化:將tree樹形數(shù)據(jù)轉(zhuǎn)換為平行數(shù)據(jù) ? ? ? ? //console.log(this.flatTree) ? ? } } </script>
<style lang = "scss" scoped> .loginModuel{ ? ? margin-left: 400px; ? ? margin-top: 100px; ? ? .tree{ ? ? ? ? .ul{ ? ? ? ? ? ? >li{ ? ? ? ? ? ? ? ? margin: 5px 0 5px 0; ? ? ? ? ? ? ? ? >img{ ? ? ? ? ? ? ? ? ? ? position: relative; ? ? ? ? ? ? ? ? ? ? top: 2.4px; ? ? ? ? ? ? ? ? ? ? left: 4px; ? ? ? ? ? ? ? ? } ? ? ? ? ? ? } ? ? ? ? ? ? .ul2{ ? ? ? ? ? ? ? ? >li{ ? ? ? ? ? ? ? ? ? ? position: relative; ? ? ? ? ? ? ? ? ? ? left: 20px; ? ? ? ? ? ? ? ? ? ? margin: 5px 0 5px 0; ? ? ? ? ? ? ? ? ? ? >img{ ? ? ? ? ? ? ? ? ? ? ? ? //transition: all ease-in-out 1s; ? ? ? ? ? ? ? ? ? ? ? ? position: relative; ? ? ? ? ? ? ? ? ? ? ? ? top: 2.4px; ? ? ? ? ? ? ? ? ? ? ? ? left: 4px; ? ? ? ? ? ? ? ? ? ? } ? ? ? ? ? ? ? ? } ? ? ? ? ? ? } ? ? ? ? } ? ? } } input[type=checkbox]{ ? ? cursor: pointer; ? ? position: relative; ? ? width: 15px; ? ? height: 15px; ? ? font-size: 14px; ? ? border: 1px solid #dcdfe6; ? ? background-color: #fff !important; ? ? &::after{ ? ? ? ? position: absolute; ? ? ? ? top: 0; ? ? ? ? background-color: #fff; ? ? ? ? border: 1px solid #ddd; ? ? ? ? color: #000; ? ? ? ? width: 15px; ? ? ? ? height: 15px; ? ? ? ? display: inline-block; ? ? ? ? visibility: visible; ? ? ? ? padding-left: 0px; ? ? ? ? text-align: center; ? ? ? ? content: ' '; ? ? ? ? border-radius: 3px; ? ? ? ? transition: all linear .1s; ? ? } ? ? &:checked::after{ ? ? ? ? content: "?"; ? ? ? ? font-size: 12px; ? ? ? ? background-color: #409eff; ? ? ? ? border: 1px solid #409eff; ? ? ? ? transition: all linear .1s; ? ? ? ? color: #fff; ? ? ? ? font-weight: bold; ? ? } } </style>
子組件主要是實現(xiàn)全選和取消全選。由于遞歸組件的原因,子組件拿不到完整的數(shù)據(jù),所以接下來的兩個功能:全選后某一個子節(jié)點取消選中則父節(jié)點取消選中、子節(jié)點全選后父節(jié)點自覺選中的功能就要在父組件中完成了。
講解:
1、設值:
樹形數(shù)據(jù)必須有pid屬性,用于向上遍歷。
2、方法:
transformData():
將層級數(shù)據(jù)轉(zhuǎn)為平行數(shù)據(jù),避免后期不停的遞歸調(diào)用消耗時間,平級數(shù)據(jù)使用一般的循環(huán)即可完成。selectnode():
由子組件傳遞過來的方法,大致分為兩個方向:選中、取消選中。選中時實現(xiàn)功能一:子節(jié)點全選后父節(jié)點自覺選中;取消選中實現(xiàn)功能二:全選后某一個子節(jié)點取消選中則父節(jié)點取消選中。getParentnode():
用于實現(xiàn)功能二。子節(jié)點取消選中后,根據(jù)pid,將在它上面級別的所有父節(jié)點列表拿到,再由方法updateParentCheck()
將父節(jié)點的check
值全部改為false
。childAllToParent():
用于實現(xiàn)功能一。遞歸調(diào)用該方法,將操作節(jié)點的父節(jié)點拿到,根據(jù)兄弟節(jié)點有相同的pid,拿到兄弟節(jié)點的個數(shù),如果兄弟節(jié)點中被選中的個數(shù)等于兄弟節(jié)點的個數(shù),則修改父節(jié)點的check
值為true
,直到到了根節(jié)點結束遞歸。
- 這個組件實現(xiàn)起來不是很難,只要是心細就能很好的完成。
- 如果后期需要使用某些數(shù)據(jù)的話,直接掛到data里就可以。
- 如果有更好的方法或者存在某些疑問,歡迎小伙伴留言!
附: (global.js => 放于component文件夾下)
import Vue from 'vue'; function capitalizeFirstLetter(string){ ? ? return string.charAt(0).toUpperCase() + string.slice(1); } const requireComponent = require.context( ? ? '.',true,/\.vue$/ ? ? //找到components文件夾下以.vue命名的文件 ) requireComponent.keys().forEach(fileName => { ? ? const componetConfig = requireComponent(fileName); ? ? let a = fileName.lastIndexOf('/'); ? ? fileName = '.' + fileName.slice(a); ? ? const componetName = capitalizeFirstLetter( ? ? ? ? fileName.replace(/^\.\//,'').replace(/\.\w+$/,'') ? ? ) ? ? Vue.component(componetName,componetConfig.default || componetConfig) })
- 由此其實可以實現(xiàn)很多遞歸組件,如側(cè)邊欄。
- 下面我放一個自己寫的側(cè)邊欄的動圖,方法比這個樹形組件要簡單些,畢竟不用考慮復選框的值。感興趣的小伙伴們可以試著實踐一下
以上就是本文的全部內(nèi)容,希望對大家的學習有所幫助,也希望大家多多支持腳本之家。
相關文章
詳解win7 cmd執(zhí)行vue不是內(nèi)部命令的解決方法
這篇文章主要介紹了詳解win7 cmd執(zhí)行vue不是內(nèi)部命令的解決方法的相關資料,這里提供了解決問題的詳細步驟,具有一定的參考價值,需要的朋友可以參考下2017-07-07vue中的事件觸發(fā)(emit)及監(jiān)聽(on)問題
這篇文章主要介紹了vue中的事件觸發(fā)(emit)及監(jiān)聽(on)問題,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2022-10-10關于vue-admin-element中的動態(tài)加載路由
這篇文章主要介紹了關于vue-admin-element的動態(tài)加載路由,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2022-08-08在Vue項目中用fullcalendar制作日程表的示例代碼
這篇文章主要介紹了在Vue項目中用fullcalendar制作日程表,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧2019-08-08unplugin-auto-import的配置以及eslint報錯解決詳解
unplugin-auto-import?解決了vue3-hook、vue-router、useVue等多個插件的自動導入,也支持自定義插件的自動導入,是一個功能強大的typescript支持工具,這篇文章主要給大家介紹了關于unplugin-auto-import的配置以及eslint報錯解決的相關資料,需要的朋友可以參考下2022-08-08