Vue树形视图解析,官方文档+常用场景

官方文档解析

前提了解:
    1,@dblclick是双击
    2,递归使用树形组件的时候,js逻辑相当于有重新走一遍。

源码

主代码 treeView1.vue

<template>
  <ul id="demo">
    <tree1
      class="item"
      :model="treeData">
    </tree1>
  </ul>
</template>

<script>
  import tree1 from '../common/tree1'
    export default {
      name: "tree-view1",
      components: {
        tree1
      },
      data(){
        return{
         treeData:{
           name: 'My Tree',
           children: [
             { name: 'hello' },
             { name: 'wat' },
             {
               name: 'child folder',
               children: [
                 {
                   name: 'child folder',
                   children: [
                     { name: 'hello' },
                     { name: 'wat' }
                   ]
                 },
                 { name: 'hello' },
                 { name: 'wat' },
                 {
                   name: 'child folder',
                   children: [
                     { name: 'hello' },
                     { name: 'wat' }
                   ]
                 }
               ]
             }
           ]
         }
        }
      },
      mounted(){

      },
      computed:{

      },
      methods:{

      }
    }

</script>

<style scoped>
  body {
    font-family: Menlo, Consolas, monospace;
    color: #444;
  }
  .item {
    cursor: pointer;
  }
  .bold {
    font-weight: bold;
  }
  ul {
    padding-left: 1em;
    line-height: 1.5em;
    list-style-type: dot;
  }
</style>

树形组件代码 tree1.vue

<template>
  <li>
    <!--@dblclick="changeType" 双击变成文件夹-->
    <div
      :class="isFolder?'bold':''"
      @click="toggle"
      @dblclick="changeType"
    >
      {{ model.name }}
      <!--是文件夹的话 有span 和 ul-->
      <span v-if="isFolder">---open:{{open}}[{{ open ? '-' : '+' }}]</span>
    </div>
    <!--非0 都是true
    v-show,v-if只要都为true才能显示
    -->
    <ul v-show="open" v-if="isFolder">
      <!--再次进来tree1的时候相当于有重新走了一边tree1组件 open默认为false-->
      <tree1
        class="item"
        v-for="(model, index) in model.children"
        :key="index"
        :model="model">
      </tree1>
      <li class="add" @click="addChild">+</li>
    </ul>
  </li>
</template>
<script>
    export default {
      name: "tree1",
      data(){
        return{
          open: false,
        }
      },
      props:{
        model:{type:Object},
      },
      mounted(){
      },
      computed:{
        isFolder: function () {
          return this.model.children &&
            this.model.children.length
        }
      },
      methods:{
        toggle: function () {
          if (this.isFolder) {
            this.open = !this.open
          }
          console.log(this.isFolder)
          console.log(this.open)
        },
        changeType: function () {//双击的时候会触发点击事件 所以创建children数组的时候直接
          if (!this.isFolder) {
            // Vue.set(this.model, 'children', [])
            this.$set(this.model, 'children', [])
            this.addChild();
            this.open = true
          }
        },
        addChild: function () {
          this.model.children.push({
            name: 'new stuff'
          })
        }
      }
    }
</script>
<style scoped>
</style>

常用场景

源码

主代码 treeView.vue

<template>
  <div class="div_tree">
    <div>
      <my-tree :data="theData" :name="menuName"></my-tree>
    </div>
  </div>
</template>
<script>
  const myData = [
    {
      id: '1',
      menuName: '基础管理',
      menuCode: '10',
      children: [
        {
          menuName: '用户管理',
          menuCode: '11'
        },
        {
          id: '12',
          menuName: '角色管理',
          menuCode: '12',
          children: [
            {
              menuName: '管理员',
              menuCode: '121'
            },
            {
              menuName: 'CEO',
              menuCode: '122'
            },
            {
              menuName: 'CFO',
              menuCode: '123'
            },
            {
              menuName: 'COO',
              menuCode: '124'
            },
            {
              menuName: '普通人',
              menuCode: '124'
            }
          ]
        },
        {
          menuName: '权限管理',
          menuCode: '13'
        }
      ]
    },
    {
      id: '2',
      menuName: '商品管理',
      menuCode: '',
      children: [
        {
          menuName: '商品一',
          menuCode: '21'
        },
        {
          id: '22',
          menuName: '商品二',
          menuCode: '22',
          children: [
            {
              menuName: '子类商品1',
              menuCode: '221'
            },
            {
              menuName: '子类商品2',
              menuCode: '222'
            }
          ]
        }
      ]
    },
    {
      id: '3',
      menuName: '订单管理',
      menuCode: '30',
      children: [
        {
          menuName: '订单列表',
          menuCode: '31'
        },
        {
          menuName: '退货列表',
          menuCode: '32',
          children: []
        }
      ]
    },
    {
      id: '4',
      menuName: '商家管理',
      menuCode: '',
    }
  ];
  import myTree from '../common/tree.vue'
  export default {
    components: {
      myTree
    },
    data () {
      return {
        theData: myData,
        menuName: 'menuName', // 显示菜单名称的属性
      }
    },
    methods: {
    }
  }
</script>
<style scoped>
</style>

树形组件代码 tree.vue

<template>
  <ul class="tree-menu">
    <li v-for="(item, index) in data">
      <span @click="toggle(item, index)">
        <i :class="['icon', item.children && item.children.length ? folderIconList[index] : 'file-text',]"></i>
        {{ item[name] || item.menuName }}
      </span>
      <tree-menu v-if="scope[index]" :data="item.children"></tree-menu>
    </li>
  </ul>
</template>

<script>
  export default {
    name: 'treeMenu',//必须命名 自己使用
    props: {
      data: Array,
      name: String,

    },
    data () {
      return {
        folderIconList: [],
        scope: {}
      }
    },
    created () {
      this.data.forEach((item, index) => {
        // console.log(index)
        // console.log(item)
        if (item.children && item.children.length) {
          this.folderIconList[index] = 'folder';//0,1,2 是文件夹
        }
      });
    },
    methods: {
      doTask (index) {
        this.$set(this.scope, index, !this.scope[index]);
        console.log(this.scope)
        this.folderIconList[index] = this.scope[index] ? 'folder-open' : 'folder'; //判断文件夹是否为打开状态
      },
      toggle (item, index) {
        console.log(index);
        console.log(item)
        if (item.children && item.children.length) {
          this.doTask(index);
        } else {
        }
      }
    }
  }
</script>

<style scoped>
  .tree-menu {
    list-style: none;
  }
  .tree-menu li {
    line-height: 2;
  }
  .tree-menu li span {
    cursor: default;
  }
  .icon {
    display: inline-block;
    width: 15px;
    height: 15px;
    background-repeat: no-repeat;
    vertical-align: -2px;
  }
  .icon.folder {
    background-image: url(../../src/assets/folder.png);
  }
  .icon.folder-open {
    background-image: url(../../src/assets/folder-open.png);
  }
  .icon.file-text {
    background-image: url(../../src/assets/file-text-o.png);
  }
  .icon.loading {
    background-image: url(../../src/assets/loading.png);
    background-size: 15px;
  }
</style>

主要讲的就是递归

猜你喜欢

转载自blog.csdn.net/etemal_bright/article/details/80540737