vue——树形目录实现

1、使用el-menu子组件递归

  • 父级菜单menu.vue
<template>
    <div class="main-sidebar" class="showSlide expandSide">
        <el-menu class="el-menu-style"
                 @select=""
                 @open="handleOpen"
                 @close="handleClose">
          <template v-for="item in fileList">
            <sub-menu :param="item" ></sub-menu>
          </template>
        </el-menu>
    </div>
</template>
<script>
  import subMenu from "./subMenu.vue"
  import {fileList} from  '../http/api'



  export default {
    data() {
      return {
        fileList:{},
      }
    },
    computed: {
      onRoutes(){
        return this.$route.path;
      },
      onRouteKeys(){
        return getParentArray(this.$route.path, this.fileList);
      }
    },
    created() {
      this.loadFile();
    },
    methods: {
      handleOpen(key, keyPath) {

      },
      handleClose(key, keyPath) {

      },
      loadFile(){
        let projectId = this.$route.params.id
        fileList(projectId).then(res => {
          this.fileList = res.data
        }).catch(err => {
            alert("当前用例为空")
        })
      }
    }
  }
</script>
<style scoped>

  .showSlide {
    animation-duration: .2s;
    animation-name: slideInLeft;
  }

  .hideSlide {
    animation-duration: .2s;
    animation-name: slideOutLeft;
  }

  .main-sidebar {
    background-color: #ffffff;
    position: fixed;
    top: 50px;
    left: 0;
    bottom: 0;
    height: calc(100vh - 50px);
    width: 44px;
    z-index: 810;
    -webkit-transition: -webkit-transform 0.3s ease-in-out, width 0.3s ease-in-out;
    -moz-transition: -moz-transform 0.3s ease-in-out, width 0.3s ease-in-out;
    -o-transition: -o-transform 0.3s ease-in-out, width 0.3s ease-in-out;
    transition: transform 0.3s ease-in-out, width 0.3s ease-in-out;
  }

  .expandSide {
    width: 280px;
  }

  .el-menu-style,
  .el-menu-style .el-menu{
    background-color: #ffffff;
  }
  .el-menu-style .el-menu-item:hover,
  .el-menu-style .el-submenu__title:hover{
    background-color: #eeeeee !important;
  }

  .el-menu-style .el-submenu .el-menu-item {
    height: 45px;
    line-height: 45px;
  }

  .el-menu-style .el-menu-item,
  .el-menu-style .el-submenu__title {
    height: 45px;
    line-height: 45px;
  }

  .main-sidebar .el-menu--collapse {
    width: 44px;
  }

  .main-sidebar .el-menu--collapse>.el-menu-item,
  .main-sidebar .el-menu--collapse>.el-submenu>.el-submenu__title {
    padding-left: 13px !important;
  }

  .vue-scrollbar{
    background-color: #ffffff !important;
    height: calc(100vh - 50px)
  }

  .main-sidebar .el-scrollbar__bar.is-vertical{
    display: none;
  }

  .sidebar{
    min-height: 450px;
  }


</style>

  • 子组件subMenu.vue
<template>
  <div class="contents">
    <div class="menu-list">
      <el-submenu :index="item.href" v-if="item.children && item.children.length>0" class="el-menu-sub" >
        <template slot="title">
            <div v-if="item.isShow == 2" v-contextmenu:contextmenu-file>
              <i  class="fa  fa-file"></i>
              <el-link :underline="false" @click="intoItem(item.id)">
                <span>{{item.name}}</span>
              </el-link>
            </div>
            <div v-else v-contextmenu:contextmenu-folder>
              <i class="fa fa-folder"></i>
              <span>{{item.name}}</span>
            </div>
        </template>
        <template v-for="child in item.children">
          <sub-menu v-if="child.children && child.children.length>0" :param="child"></sub-menu>
          <el-menu-item :index="child.href" v-else >
              <div v-if="child.isShow == 1" v-contextmenu:contextmenu-folder>
                 <i class="fa fa-folder"></i>
                <span>{{item.name}}</span>
              </div>
              <div v-else v-contextmenu:contextmenu-file>
                <i  class="fa fa-file"></i>
                <el-link :underline="false" @click="intoItem(child.id)">
                  <span>{{child.name}}</span>
                </el-link>
              </div>
          </el-menu-item>
        </template>
      </el-submenu>
      <el-menu-item :index="item.href" v-else class="el-menu-each">
          <div v-if="item.isShow == 2" v-contextmenu:contextmenu-file>
            <i  class="fa  fa-file"></i>
            <el-link :underline="false" @click="intoItem(item.id)">
              <span>{{item.name}}</span>
            </el-link>
          </div>
          <div v-else v-contextmenu:contextmenu-folder>
            <i class="fa fa-folder"></i>
            <span>{{item.name}}</span>
          </div>
      </el-menu-item>
    </div>
  </div>
</template>
<script>
  import subMenu from "./subMenu.vue"



  export default {
    name: 'subMenu',
    props: ['param'],
    data() {
      return {
        item: this.param
      }
    },
    components: {
      subMenu,
    }
  }
</script>
<style scoped>
  .el-menu .fa {
    margin-right: 10px;
  }
  .box {
    width: 100%;
  }
  .el-dialog{
    display: flex;
    flex-direction: column;
    margin:0 !important;
    position:absolute;
    top:50%;
    left:50%;
    transform:translate(-50%,-50%);
    /*height:600px;*/
    max-height:calc(100% - 30px);
    max-width:calc(100% - 30px);
  }
  .el-dialog .el-dialog__body{
    flex:1;
    overflow: auto;
  }
</style>

2、使用开源组件v-tree

  • v-tree.css
.ztree * {
  moz-user-select: -moz-none;
  -moz-user-select: none;
  -o-user-select:none;
  -khtml-user-select:none;
  -webkit-user-select:none;
  -ms-user-select:none;
  user-select:none;


  padding:0; margin:0; font-size:12px; font-family: Verdana, Arial, Helvetica, AppleGothic, sans-serif}
.ztree {margin:0; padding:5px; color:#333}
.ztree li{padding:0; margin:0; list-style:none; line-height:17px; text-align:left; white-space:nowrap; outline:0}
.ztree li ul{ margin:0; padding:0 0 0 18px}
.ztree li ul.line{ background:url(../img/line_conn.png) 0 0 repeat-y;}

.ztree li a {padding-right:3px; margin:0; cursor:pointer; height:21px; color:#333; background-color: transparent; text-decoration:none; vertical-align:top; display: inline-block}
.ztree li a:hover {text-decoration:underline}
.ztree li a.curSelectedNode {padding-top:0px; background-color:#e5e5e5; color:black; height:21px; opacity:0.8;}
.ztree li a.curSelectedNode_Edit {padding-top:0px; background-color:#e5e5e5; color:black; height:21px; border:1px #666 solid; opacity:0.8;}
.ztree li a.tmpTargetNode_inner {padding-top:0px; background-color:#aaa; color:white; height:21px; border:1px #666 solid;
  opacity:0.8; filter:alpha(opacity=80)}
.ztree li a.tmpTargetNode_prev {}
.ztree li a.tmpTargetNode_next {}
.ztree li a input.rename {height:14px; width:80px; padding:0; margin:0;
  font-size:12px; border:1px #585956 solid; *border:0px}
.ztree li span {line-height:21px; margin-right:2px}
.ztree li span.button {line-height:0; margin:0; padding: 0; width:21px; height:21px; display: inline-block; vertical-align:middle;
  border:0 none; cursor: pointer;outline:none;
  background-color:transparent; background-repeat:no-repeat; background-attachment: scroll;
  background-image:url("../img/v-tree.png");}

.ztree li span.button.chk {width:13px; height:13px; margin:0 2px; cursor: auto}
.ztree li span.button.chk.checkbox_false_full {background-position: -5px -5px;}
.ztree li span.button.chk.checkbox_false_full_focus {background-position: -5px -26px;}
.ztree li span.button.chk.checkbox_false_part {background-position: -5px -48px;}
.ztree li span.button.chk.checkbox_false_part_focus {background-position: -5px -68px;}
.ztree li span.button.chk.checkbox_false_disable {background-position: -5px -89px;}
.ztree li span.button.chk.checkbox_true_full {background-position: -26px -5px;}
.ztree li span.button.chk.checkbox_true_full_focus {background-position: -26px -26px;}
.ztree li span.button.chk.checkbox_true_part {background-position: -26px -48px;}
.ztree li span.button.chk.checkbox_true_part_focus {background-position: -26px -68px;}
.ztree li span.button.chk.checkbox_true_disable {background-position: -26px -89px;}
.ztree li span.button.chk.radio_false_full {background-position: -47px -5px;}
.ztree li span.button.chk.radio_false_full_focus {background-position: -47px -26px;}
.ztree li span.button.chk.radio_false_part {background-position: -47px -47px;}
.ztree li span.button.chk.radio_false_part_focus {background-position: -47px -68px;}
.ztree li span.button.chk.radio_false_disable {background-position: -47px -89px;}
.ztree li span.button.chk.radio_true_full {background-position: -68px -5px;}
.ztree li span.button.chk.radio_true_full_focus {background-position: -68px -26px;}
.ztree li span.button.chk.radio_true_part {background-position: -68px -47px;}
.ztree li span.button.chk.radio_true_part_focus {background-position: -68px -68px;}
.ztree li span.button.chk.radio_true_disable {background-position: -68px -89px;}

.ztree li span.button.switch {width:21px; height:21px}
.ztree li span.button.root_open{background-position:-105px -63px}
.ztree li span.button.root_close{background-position:-126px -63px}
.ztree li span.button.roots_open{background-position: -105px 0;}
.ztree li span.button.roots_close{background-position: -126px 0;}
.ztree li span.button.center_open{background-position: -105px -21px;}
.ztree li span.button.center_close{background-position: -126px -21px;}
.ztree li span.button.bottom_open{background-position: -105px -42px;}
.ztree li span.button.bottom_close{background-position: -126px -42px;}
.ztree li span.button.noline_open{background-position: -105px -84px;}
.ztree li span.button.noline_close{background-position: -126px -84px;}
.ztree li span.button.root_docu{ background:none;}
.ztree li span.button.roots_docu{background-position: -84px 0;}
.ztree li span.button.center_docu{background-position: -84px -21px;}
.ztree li span.button.bottom_docu{background-position: -84px -42px;}
.ztree li span.button.noline_docu{ background:none;}

.ztree li span.button.ico_open{margin-right:2px; background-position: -147px -21px; vertical-align:top; *vertical-align:middle}
.ztree li span.button.ico_close{margin-right:2px; background-position: -147px 0; vertical-align:top; *vertical-align:middle}
.ztree li span.button.ico_docu{margin-right:2px; background-position: -147px -42px; vertical-align:top; *vertical-align:middle}
.ztree li span.button.edit {margin-left:2px; margin-right: -1px; background-position: -189px -21px; vertical-align:top; *vertical-align:middle}
.ztree li span.button.edit:hover {
  background-position: -168px -21px;
}
.ztree li span.button.remove {margin-left:2px; margin-right: -1px; background-position: -189px -42px; vertical-align:top; *vertical-align:middle}
.ztree li span.button.remove:hover {
  background-position: -168px -42px;
}
.ztree li span.button.add {margin-left:2px; margin-right: -1px; background-position: -189px 0; vertical-align:top; *vertical-align:middle}
.ztree li span.button.add:hover {
  background-position: -168px 0;
}
.ztree li span.button.ico_loading{margin-right:2px;  vertical-align:top; *vertical-align:middle}

ul.tmpTargetzTree {background-color:#FFE6B0; opacity:0.8; filter:alpha(opacity=80)}

span.tmpzTreeMove_arrow {width:16px; height:21px; display: inline-block; padding:0; margin:2px 0 0 1px; border:0 none; position:absolute;
  background-color:transparent; background-repeat:no-repeat; background-attachment: scroll;
  background-position:-168px -84px; background-image:url("../img/v-tree.png"); }

ul.ztree.zTreeDragUL {margin:0; padding:0; position:absolute; width:auto; height:auto;overflow:hidden; background-color:#cfcfcf; border:1px #00B83F dotted; opacity:0.8; filter:alpha(opacity=80)}
.ztreeMask {z-index:10000; background-color:#cfcfcf; opacity:0.0; filter:alpha(opacity=0); position:absolute}

  • tree.vue
<template>
  <div>
    <ul class="ztree">
      <vTree v-for="(node,index) in treeData"
             :key="index"
             :checkBoxType="checkBoxType"
             :allOpen="allOpen"
             :beforeClick="beforeClick"
             :checkBox="checkBox"
             :nodeTrigger="nodeTrigger"
             :index="index"
             :tree="node"
             :first="index===0"
             :last="treeData.length-1===index"
             :currentArray="treeData"
             :parentTree="node.parentTree"
             :rootData="treeData"
             :checkBoxCallInit="checkBoxCallInit"
             :checkBoxCall="checkBoxCall"
             :clickNode="clickNode"
             :hiddenLine="hiddenLine"
             :async="async"
             :asyncCall="asyncCall"
      />
    </ul>
  </div>
</template>

<script>
  import vTree from './tree-core'

  export default {
    components: {vTree},
    name: "tree",
    props: {
      treeNode: {
        type: Array,
        default: function () {
          return [];
        },
        required: true,
      },
      allOpen: {
        type: Boolean,
        default: null,
        required: false,
      },
      nodeTrigger: {
        type: Boolean,
        default: false,
        required: false,
      },
      checkBox: {
        type: Boolean,
        default: false,
        required: false,
      },
      checkBoxType: {
        type: Boolean,
        default: true,
        required: false,
      },
      beforeClick: {
        type: Function,
        default: null
      },
      clickNode: {
        type: Function,
      },
      asyncCall: {
        type: Function,
      },
      hiddenLine: {
        type: Boolean,
        default: false,
        required: false,
      },
      async: {
        type: Boolean,
        default: false,
        required: false,
      },
    },
    data() {
      return {
        treeData: [],
        line: '',
        first: true,
        allOpens: this.allOpen,
        checkedBoxCallArr: [],
      }
    },
    methods: {
      init() {
        let tempList = JSON.parse(JSON.stringify(this.treeNode));

        let initTree = (tree, parent) => {
          for (let index = 0; index < tree.length; index++) {
            let m = tree[index];
            if (!m.hasOwnProperty("id")) {
              m.id = m.hasOwnProperty("id") ? m.id : null;
            }
            if (!m.hasOwnProperty("open")) {
              m.open = m.hasOwnProperty("open") ? m.open : false;
            }
            if (!m.hasOwnProperty("checked")) {
              m.checked = m.hasOwnProperty("checked") ? m.checked : false;
            }
            if (!m.hasOwnProperty("checkBox")) {
              m.checkBox = m.hasOwnProperty("checkBox") ? m.checkBox : false;
            }
            if (!m.hasOwnProperty("nodeTrigger")) {
              m.nodeTrigger = m.hasOwnProperty("nodeTrigger") ? m.nodeTrigger : false;
            }
            if (!m.hasOwnProperty("checkBoxType")) {
              m.checkBoxType = this.checkBoxType
            }
            if (!m.hasOwnProperty("last")) {
              m.last = m.hasOwnProperty("last") ? m.last : false;
            }
            if (!m.hasOwnProperty("first")) {
              m.first = m.hasOwnProperty("first") ? m.first : false;
            }
            if (!m.hasOwnProperty("active")) {
              m.active = m.hasOwnProperty("active") ? m.active : false;
            }
            if (!m.hasOwnProperty("async")) {
              m.async = this.async;
            }
            if (!m.hasOwnProperty("hiddenLine")) {
              m.hiddenLine = this.hiddenLine;
            }
            if (!m.hasOwnProperty("parentTree")) {
              m.parentTree = parent ? parent : null;
            }

            m.children = m.children || [];
            if (m.children.length > 0)
              initTree(m.children, m);
          }
        };
        initTree(tempList, null);

        this.treeData = tempList;
        this.line = 'line';
        if (this.first)
          this.$emit('call', this.treeData);
      },
      changeStatus() {
        let changeOpen = (data) => {
          data.forEach(d => {
            d.open = this.allOpen;
            if (d.children) changeOpen(d.children);
          });
        };
        changeOpen(this.treeData);
      },
      checkBoxCallInit(arr) {
        arr.forEach(a => {
          this.checkedBoxCallArr.push(a);
        });
      },
      checkBoxCall(arr, isAdd) {
        if (isAdd)
          arr.forEach(a => {
            this.checkedBoxCallArr.push(a);
          });
        else {
          arr.forEach(a => {
            if (this.checkBoxCall.length === 0)
              return;
            let key = (a.id ? a.id : null) + a.index + a.name;

            this.checkedBoxCallArr.forEach((ss, index) => {
              if (((ss.id ? ss.id : null) + ss.index + ss.name) === key) {
                this.checkedBoxCallArr.splice(index, 1);
              }
            });
          });
        }
        this.$emit('checkBoxCall', this.checkedBoxCallArr);
      },
    },
    created() {
      this.init();
    },
    update() {
    },
    mounted() {
      /*复选框回调*/
      this.$emit('checkBoxCall', this.checkedBoxCallArr);
    },
    watch: {
      allOpen() {
        this.changeStatus()
      }
    }
  }
</script>

<style scoped>
  @import "../../../../static/css/v-tree.css";
</style>

  • tree-core.vue
<template>
  <li>
      <span v-if="vif()" title=""
            @click="vShow(tree)"
            class="button  switch"
            :class="vTreeFirstSpan()"></span>
    <span v-else title="" class="button switch "
          :class="classes()"></span>

    <span v-if="checkBox" @click="selectCheckBox(tree)" class="button chk"
          :class="tree.checked?'checkbox_true_full':'checkbox_false_full'"></span>

    <a target="_blank"
       style=""
       @click="selectNode"
       :class="aClass()"
       :title="tree.name">
      <span :title="tree.name" class="button" :class="iconCss()" :style="load()"></span>
      <span class="node_name">{{tree.name}}</span>
    </a>
    <ul :class="line">
      <treeCore
        v-for="(tr,i) in tree.children"
        v-show="tree.open"
        :key="i"
        :checkBoxType="checkBoxType"
        :allOpen="tr.allOpen"
        :first="false"
        :checkBox="checkBox"
        :nodeTrigger="nodeTrigger"
        :index="i"
        :tree="tr"
        :currentArray="tree.children"
        :parentTree="tr.parentTree"
        :rootData="rootData"
        :clickNode="clickNode"
        @checkedBoxV="checkedBoxV"
        :beforeClick="beforeClick"
        :checkBoxCallInit="checkBoxCallInit"
        :checkBoxCall="checkBoxCall"
        :last="tree.children.length-1===i"
        :hiddenLine="tr.hiddenLine"
        :async="async"
        :asyncCall="asyncCall"

      />
    </ul>
  </li>

</template>

<script>

  export default {
    name: "treeCore",
    props: {
      tree: {
        type: Object,
        required: true,
      },
      allOpen: {
        type: Boolean,
        default: null,
        required: false,
      },
      nodeTrigger: {
        type: Boolean,
        default: false,
        required: false,
      },
      checkBox: {
        type: Boolean,
        default: false,
        required: false,
      },
      checkBoxType: {
        type: Boolean,
        default: true,
        required: false,
      },
      beforeClick: {
        type: Function,
        default: null
      },
      last: {
        type: Boolean,
        default: null,
        required: false,
      },
      first: {
        type: Boolean,
        default: true,
        required: false,
      },
      currentArray: {
        type: Array,
        required: true,
      },
      index: {
        type: Number,
        required: true,
      },
      rootData: {
        type: Array,
        required: true,
      },
      parentTree: {
        type: Object,
        required: false,
      },
      checkBoxCallInit: {
        type: Function,
      },
      checkBoxCall: {
        type: Function,
      },
      clickNode: {
        type: Function,
      },
      asyncCall: {
        type: Function,
      },
      hiddenLine: {
        type: Boolean,
        default: false,
        required: false,
      },
      async: {
        type: Boolean,
        default: false,
        required: false,
      },
    },
    data() {
      return {
        line: '',
        currentTree: this.tree,
        asyncLoading: false,
      }
    },
    methods: {
      coreInit() {
        this.line = this.hiddenLine ? '' : this.currentArray.length - 1 === this.index ? '' : 'line';
        if (this.tree.parentTree && this.tree.checked) {
          /*方案一 Scheme 1*/
          let checkedBoxArr = [];
          checkedBoxArr.push(this.tree);
          let selectParent = (data) => {
            if (!data.checked) {
              data.checked = this.tree.checked;
              checkedBoxArr.push(data);
            }
            if (data.parentTree) {
              selectParent(data.parentTree);
            } else {
              this.checkBoxCallInit(checkedBoxArr);
            }
          };
          selectParent(this.currentTree);
          /*方案二 Scheme 2*/
          //this.$emit('checkedBoxV')
        }
      },
      checkedBoxV() {
        this.tree.checked = true;
        this.$emit('checkedBoxV')
      },
      pNode(tree) {
        return tree.open;
      },
      vShow(tree) {
        /*需要有异步加载  need add async loading*/
        /*默认异步加载给他按钮 当加载后才能判别时候有子节点 */
        if (this.async && !tree.open && tree.children.length === 0) {
          this.asyncCall.call(this, tree, this.asyncBack);
          this.asyncLoading = true;
        }
        tree.open = !tree.open;
      },
      asyncBack(requestDataArr) {
        if (typeof requestDataArr)
          this.addNode(requestDataArr);
        this.asyncLoading = false;
      },
      selectNode() {
        let isClick = this.beforeClick.call(this, this.tree);
        if (isClick) {
          //清除其它
          let pro = null;
          let clearStyle = (data) => {
            for (let i = 0; i < data.length; i++) {
              let d = data[i];
              if (d.active) {
                pro = d;
                d.active = !d.active;
              } else if (d.children) {
                clearStyle(d.children);
              }
            }
          };
          clearStyle(this.rootData);
          this.tree.active = true;
          if (this.nodeTrigger) {
            this.tree.open = !this.tree.open;
          }
          this.clickNode.call(this, this.tree, pro);
        }
      },
      addNode(arr) {
        try {
          arr.forEach(a => {
            this.tree.children.push({
              id: a.id ? a.id : null,
              name: a.name,
              open: a.open ? a.open : false,
              checked: a.checked ? a.checked : false,
              checkBox: a.checkBox ? a.checkBox : false,
              nodeTrigger: a.nodeTrigger ? a.nodeTrigger : this.nodeTrigger,
              checkBoxType: this.checkBoxType,
              last: false,
              first: false,
              active: false,
              async: this.async,
              hiddenLine: this.hiddenLine,
              parentTree: this.tree,
              children: [],
            });
          });
        } catch (e) {
          console.error('The asynchronous callback parameter must be an array,异步回调参数必须是数组');
        }
      },
      selectCheckBox(tree) {
        tree.checked = !tree.checked;
        let checkedBoxArr = [];
        checkedBoxArr.push(tree);
        if (this.checkBoxType) {
          /*级联*/
          let changeChecked = (data) => {
            data.forEach(d => {
              checkedBoxArr.push(d);
              d.checked = tree.checked;
              if (d.children) changeChecked(d.children);
            });
          };
          changeChecked(tree.children);

          let checkChildren = (data) => {
            for (let i = 0; i < data.length; i++) {
              if (data[i].checked)
                return true;
            }
          };
          let selectParent = (data) => {
            if (data.children.length > 1) {
              const childExistsThis = [];
              data.children.forEach((m, index) => {
                if (index !== this.index)
                  childExistsThis.push(m);
              });
              if (childExistsThis && data.checked && checkChildren(childExistsThis))
                return;
            }
            checkedBoxArr.push(data);
            data.checked = tree.checked;
            if (data.parentTree) selectParent(data.parentTree);
          };
          if (this.parentTree)
            selectParent(this.parentTree);
        }

        this.checkBoxCall(checkedBoxArr, tree.checked);
      }
    },
    created() {
      this.coreInit();
    },
    computed: {
      vif() {
        return function () {
          return this.async ? true : this.tree.children.length > 0;
        }
      },
      vTreeFirstSpan() {
        return function () {
          return this.hiddenLine ? this.tree.open ? 'noline_open treenode_switch' : 'noline_close treenode_switch' :
            this.currentArray.length - 1 === this.index ? this.tree.open ? 'bottom_open' : 'bottom_close'
              :
              this.tree.open ? 'roots_open' : 'roots_close';
        }
      },
      classes() {
        return function () {
          return this.hiddenLine ?
            'noline_docu'
            :
            this.first ?
              'roots_docu'
              :
              this.currentArray.length - 1 === this.index ?
                'bottom_docu'
                :
                'center_docu'
        }
      },
      iconCss() {
        return function () {
          return this.tree.children.length > 0 ? this.tree.open ? 'ico_open' : 'ico_close' : 'ico_docu';
        }
      },
      load() {
        return function () {
          return this.asyncLoading ?
            'background:url(../../static/img/loading.gif) 0 0 no-repeat' : ''
        }
      },
      aClass() {
        return function () {
          return this.tree.active ? 'curSelectedNode' : '';
        }
      }
    },
    watch: {
      tree: {
        handler(oldV, newV) {
          if (newV.checked)
            this.tree.checked = newV.checked;
        },
        deep: true
      },
    }
  }
</script>

<style scoped>
  @import "../../../../static/css/v-tree.css";
</style>

  • vtree-demo.vue
<template>
  <div style="height: auto">
    <div class="main">
      <ul>
        <li>
          <Tree
            :treeNode="treeNode"
            :clickNode="clickNode"
            :beforeClick="beforeClick"
            :hiddenLine="hiddenLine"
            :async="async"
            @call='callAsync'
            :asyncCall="asyncCall"

            :nodeTrigger="nodeTrigger"
          />
        </li>
      </ul>
    </div>

  </div>

</template>

<script>
  import Tree from "./tree";

  export default {
    components: {Tree},
    data() {
      return {
        treeNode: [],
        nodeTrigger: false,
        // 所有节点
        trees: [],
        hiddenLine: false,
        async: true,
      }
    },
    methods: {
      beforeClick(node) {
        //可操作内部
        return true;
      },
      /*回调初始化后的数据 以后修改tree实现对节点的操作即可*/
      call(data) {
        console.log('data', data);
        // this.trees = data;
      },
      callAsync(data) {
        //this.trees = data;
      },
      /*点击节点信息 上个点击节点信息*/
      clickNode(data, oldData) {
        /*if(data.children){
          data.children.push({
            id: (new Date()).getTime(),
            name:'新增节点',
            children:[]
          });
        }else{
        }*/
        // console.log(data);
        //data.open=true;
      },
      /*异步回调函数 data 当前节点数据 call 回调函数*/
      asyncCall(data, call) {
        setTimeout(function () {
          let hm = '' + (new Date()).getTime();
          let addNode = [
            {id: hm, name: "children node" + hm.substr(hm.length - 4, hm.length)},
          ];
          console.log(data.id)
          // call(addNode);
          call([])
        }, 800);
      }
    },
    mounted() {
      // this.allOpen = true;
    },
    created() {
      this.treeNode = [
        {
          id: "1",
          name: "父节点22 - 折叠",
          open: true,
          // 文件夹open = true/false
          // 文件:不显示图像

          // 添加右键弹出操作
          children: [
            {id: "1-1", name: "叶子节点221",open: true},
            {id: "1-2", name: "叶子节点222",open: true},
            {id: "1-3", name: "叶子节点223",open: true},
            {id: "1-4", name: "叶子节点224",open: true}
          ]
        }, {
          id: "2",
          name: "父节点23 - 折叠",
          children: [
            {id: "2-1", name: "叶子节点231"},
            {id: "2-2", name: "叶子节点232"},
            {id: "2-3", name: "叶子节点233"},
            {id: "2-4", name: "叶子节点234"}
          ]
        }, {
          open: true,
          id: "3",
          name: "父节点24 - 折叠",
          children: [
            {
              id: "2-1-1", name: "叶子节点232", open: true,
              children: [
                {id: "2-1-3", name: "叶子节点2313"},
                {id: "2-2-3", name: "叶子节点2323"},
                {id: "2-3-3", name: "叶子节点2333"},
                {id: "2-4-3", name: "叶子节点2343"}
              ]
            },
          ]
        },
      ];
    }
  }
</script>

<style scoped>
  .main ul li {
    list-style: none;
    float: left;
    width: 25%;

  }
</style>


3、使用el-tree动态加载

你可能感兴趣的:(前端)