溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務(wù)條款》

vue遞歸組件之如何實現(xiàn)簡單樹形控件

發(fā)布時間:2021-07-20 14:26:59 來源:億速云 閱讀:208 作者:小新 欄目:web開發(fā)

這篇文章主要介紹vue遞歸組件之如何實現(xiàn)簡單樹形控件,文中介紹的非常詳細(xì),具有一定的參考價值,感興趣的小伙伴們一定要看完!

1、遞歸組件-簡單樹形控件預(yù)覽及問題

vue遞歸組件之如何實現(xiàn)簡單樹形控件 

在編寫樹形組件時遇到的問題:

  • 組件如何才能遞歸調(diào)用?

  • 遞歸組件點擊事件如何傳遞?


2、樹形控件基本結(jié)構(gòu)及樣式

<template>
 <ul class="vue-tree">
  <li class="tree-item">
   <div class="tree-content"><!--節(jié)點內(nèi)容-->
    <div class="expand-arrow"></div><!--展開或收縮節(jié)點按鈕-->
    <div class="tree-label">小學(xué)</div><!--節(jié)點文本內(nèi)容-->
   </div>
   <ul class="sub-tree"><!--子節(jié)點-->
    <li class="tree-item expand">
     <div class="tree-content">
      <div class="expand-arrow"></div>
      <div class="tree-label">語文</div>
     </div>
    </li>
    <li class="tree-item">
     <div class="tree-content">
      <div class="expand-arrow"></div>
      <div class="tree-label">數(shù)學(xué)</div>
     </div>
    </li>
   </ul>
  </li>
 </ul>
</template>

<style lang="stylus">
.vue-tree{
 list-style: none;
 padding: 0;
 margin: 0;
 .tree-item{
  cursor: pointer;
  transition: background-color .2s;
  .tree-content{
   position: relative;
   padding-left: 28px;
   &:hover{
    background-color: #f0f7ff;
   }
  }
  .expand-arrow{
   position: absolute;
   top: 0;
   left: 0;
   width: 28px;
   height: 28px;
   cursor: pointer;
   &::after{
    position: absolute;
    top: 50%;
    left: 50%;
    display: block;
    content: ' ';
    border-width: 5px;
    border-style: solid;
    border-color: transparent;
    border-left-color: #ccc;
    margin: -5px 0 0 -2.5px;
    transition: all .2s;
   }
  }
  &.expand{
   &>.tree-content{
    background-color: #f0f7ff;
    &>.expand-arrow{
     &::after{
      transform: rotate(90deg);
      margin: -2.5px 0 0 -5px;
     }
    }
   }
  }
  .tree-label{
   height: 28px;
   line-height: 28px;
   font-size: 14px;
  }
  .sub-tree{
   display: none;
   list-style: none;
   padding: 0 0 0 28px;
   margin: 0;
  }
  &.expand>.sub-tree{
   display: block;
  }
  &.no-child{
   &>.tree-content{
    &>.expand-arrow{
     display: none;
    }
   }
  }
 }
}
</style>

3、組件目錄及數(shù)據(jù)結(jié)構(gòu)

目錄結(jié)構(gòu)

vue-tree

VueTree.vue
TreeItem.vue

樹形控件數(shù)據(jù)結(jié)構(gòu)

let treeData = [
 {
  text: "一級", // 顯示的文字
  expand: false, // 默認(rèn)是否展開
  children: [ // 子節(jié)點
   {
    text: "一級-1",
    expand: false,
   },
   {
    text: "一級-2",
    expand: false,
    children: [
     {
      text: "一級-2-1",
      expand: false,
     },
     {
      text: "一級-2-2",
      expand: false,
     }
    ]
   }
  ]
 }
];

3.1、 TreeItem.vue 代碼

<template>
 <li class="tree-item" :class="{expand: isExpand, 'no-child': !treeItemData.children || treeItemData.children.length === 0}">
  <div class="tree-content" @click="_clickEvent">
   <div class="expand-arrow" @click.stop="expandTree()"></div>
   <div class="tree-label">{{treeItemData.text}}</div>
  </div>
  <ul class="sub-tree" v-if="treeItemData.children && treeItemData.children.length > 0">
   <!--TreeItem組件中調(diào)用TreeItem組件-->
   <TreeItem
    v-for="item in treeItemData.children"
    :tree-item-data="item"
    :key="uuid()"
    :tree-click-event="treeClickEvent"></TreeItem>
  </ul>
 </li>
</template>

<script>
 export default {
  name: "TreeItem",
  props: {
   treeItemData: {
    type: Object,
    default(){
     return {};
    }
   },
   // 節(jié)點點擊事件
   treeClickEvent: {
    type: Function,
    default() {
     return function () {};
    }
   }
  },
  data(){
   return {
    // 節(jié)點是否展開
    isExpand: this.treeItemData.expand || false
   }
  },
  methods: {
   // 展開/收縮
   expandTree(flag){
    if(!this.treeItemData.children || this.treeItemData.children.length === 0){
     return;
    }
    if(typeof flag === 'undefined'){
     flag = !this.isExpand;
    }else{

     flag = !!flag;
    }
    this.isExpand = flag;
   },
   // 創(chuàng)建一個唯一id
   uuid(){
    let str = Math.random().toString(32);
    str = str.substr(2);
    return str;
   },
   // 節(jié)點點擊事件
   _clickEvent(){
    // 如果有傳遞事件函數(shù),則調(diào)用事件函數(shù)并傳遞當(dāng)前節(jié)點數(shù)據(jù)及組件
    if(this.treeClickEvent && typeof this.treeClickEvent === 'function'){
     this.treeClickEvent(this.treeItemData, this);
    }
   }
  }
 }
</script>

3.1.1、解決 組件如何才能遞歸調(diào)用? 問題

在組件模板內(nèi)調(diào)用自身 必須明確定義組件的name屬性 ,并且遞歸調(diào)用時組件名稱就是name屬性。如在 TreeItem.vue 組件中組件的name名稱為'TreeItem',那么在template中調(diào)用時組件名稱就必須是 <TreeItem> 。

當(dāng)然也可以全局注冊組件,具體可以查看vue官方文檔 遞歸組件

3.1.2、解決 遞歸組件點擊事件如何傳遞? 問題

我這里的解決方案是使用 props 將事件函數(shù)傳遞進(jìn)來,在點擊節(jié)點的時候調(diào)用事件函數(shù),并把相應(yīng)的數(shù)據(jù)傳遞進(jìn)去。

之前也嘗試過使用 $emit 的形式并把數(shù)據(jù)傳遞過去,由于是遞歸組件,這樣一直 $emit ,到最外層時傳遞的數(shù)據(jù)就變了,比如傳遞是第3層節(jié)點的數(shù)據(jù),到最后執(zhí)行時數(shù)據(jù)就變成第1層節(jié)點的數(shù)據(jù)了

4、 VueTree.vue 組件

<template>
 <ul class="vue-tree">
  <TreeItem
    v-for="(item, index) in treeData"
    :key="index"
    :treeItemData="item"
    :tree-click-event="treeClickEvent"></TreeItem>
 </ul>
</template>

<script>
 import TreeItem from "./TreeItem";
 export default {
  name: "VueTreeMenu",
  components: {
   TreeItem
  },
  props: {
   // 樹形控件數(shù)據(jù)
   treeData: {
    type: Array,
    default(){
     return [];
    }
   },
   // 節(jié)點點擊事件
   treeClickEvent: {
    type: Function,
    default() {
     return function () {};
    }
   }
  }
 }
</script>

<style lang="stylus">
.vue-tree{
 list-style: none;
 padding: 0;
 margin: 0;
 .tree-item{
  cursor: pointer;
  transition: background-color .2s;
  .tree-content{
   position: relative;
   padding-left: 28px;
   &:hover{
    background-color: #f0f7ff;
   }
  }
  .expand-arrow{
   position: absolute;
   top: 0;
   left: 0;
   width: 28px;
   height: 28px;
   cursor: pointer;
   &::after{
    position: absolute;
    top: 50%;
    left: 50%;
    display: block;
    content: ' ';
    border-width: 5px;
    border-style: solid;
    border-color: transparent;
    border-left-color: #ccc;
    margin: -5px 0 0 -2.5px;
    transition: all .2s;
   }
  }
  &.expand{
   &>.tree-content{
    background-color: #f0f7ff;
    &>.expand-arrow{
     &::after{
      transform: rotate(90deg);
      margin: -2.5px 0 0 -5px;
     }
    }
   }
  }
  .tree-label{
   height: 28px;
   line-height: 28px;
   font-size: 14px;
  }
  .sub-tree{
   display: none;
   list-style: none;
   padding: 0 0 0 28px;
   margin: 0;
  }
  &.expand>.sub-tree{
   display: block;
  }
  &.no-child{
   &>.tree-content{
    /*padding-left: 0;*/
    &>.expand-arrow{
     display: none;
    }
   }
  }
 }
}
</style>

5、使用樹形組件

<template>
 <div class="app" id="app">
  <VueTree :tree-data="treeData2" :tree-click-event="treeClickEvent"></VueTree>
 </div>
</template>

<script>
import VueTree from "./components/vue-tree/VueTree";

export default {
 name: 'app',
 data(){
  return {
   treeData2: [
    {
     text: "一級", // 顯示的文字
     expand: false, // 默認(rèn)是否展開
     children: [
      {
       text: "二級-1",
       expand: false,
      },
      {
       text: "二級-2",
       expand: false,
       children: [
        {
         text: "三級-1",
         expand: false,
        },
        {
         text: "三級-2",
         expand: false,
         children: [
          {
           text: "四級-1",
           expand: false,
          }
         ]
        }
       ]
      }
     ]
    },
    {
     text: "一級-2",
     expand: false
    }
   ]
  }
 },
 methods: {
  treeClickEvent(item, treeItem){
   console.log(item);
  }
 },
 components: {
  VueTree
 }
}
</script>

以上是“vue遞歸組件之如何實現(xiàn)簡單樹形控件”這篇文章的所有內(nèi)容,感謝各位的閱讀!希望分享的內(nèi)容對大家有幫助,更多相關(guān)知識,歡迎關(guān)注億速云行業(yè)資訊頻道!

向AI問一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報,并提供相關(guān)證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權(quán)內(nèi)容。

vue
AI