vue组件-无限级目录树

854 阅读8分钟

码云地址(demo实例): gitee.com/big-sun/men…

  • 调用目录树组件的父组件
<template>
  <div id="app">
    <wrap-left-slide
      :menuarr="arr"
      :selectindex="flagIndex"
      @selectitem="selectItem"
    >无限级目录树</wrap-left-slide>
  </div>
</template>

<script>
import menuTree from "./components/recursice-tree/wrap-recursion.vue";
export default {
  name: "App",
  data() {
    return {
      flagIndex: "",
      arr: [//数据源:注意数据格式,不能乱写
        {
          name: "主要职责1",
          mark: "8142754caa2a4e01bed712888bb5be3c",
          pid: "main-responsibilities",
          headerIconActive: "el-icon-user-solid",
          headerIconNormal: "el-icon-user",
          footerIconActive: "el-icon-warning",
          footerIconNormal: "el-icon-warning-outline"
        },
      ]
    };
  },
  components: {
    "wrap-left-slide": menuTree
  },
  mounted(){
   setTimeout(() => {
    this.flagIndex='ab228h99bg6d28274b13c183fab3ga5a';
    this.arr=[//这个结构很关键,子项的pid需要等于父项的mark(牢记)
        {
          name: "主要职责",
          mark: "8142754caa2a4e01bed712888bb5be3c",
          pid: "main-responsibilities",
          headerIconActive: "el-icon-user-solid",
          headerIconNormal: "el-icon-user",
          footerIconActive: "el-icon-warning",
          footerIconNormal: "el-icon-warning-outline"
        },
        {
          name: "内设机构",
          mark: "10b14bfc399c42e2b88b98a95855df3d",
          pid: "Internal-organization",
          headerIconActive: "el-icon-user-solid",
          headerIconNormal: "el-icon-user",
          footerIconActive: "el-icon-warning",
          footerIconNormal: "el-icon-warning-outline"
        },
        {
          name: "主要负责人",
          mark: "e41a3dcc76db467a912d9b828c87fbfc",
          pid: "principal-responsible-person",
          headerIconActive: "el-icon-user-solid",
          headerIconNormal: "el-icon-user",
          footerIconActive: "el-icon-warning",
          footerIconNormal: "el-icon-warning-outline"
        },
        {
          name: "训练基地",
          mark: "d945a2c553c243c0b6d515ad89bd6d0d",
          pid: "training-base",
          headerIconActive: "el-icon-user-solid",
          headerIconNormal: "el-icon-user",
          footerIconActive: "el-icon-warning",
          footerIconNormal: "el-icon-warning-outline"
        },
        {
          name: "联系方式",
          mark: "8e2a990e6b354d69b3ca631675ab2b43",
          pid: "contact-information",
          headerIconActive: "el-icon-user-solid",
          headerIconNormal: "el-icon-user",
          footerIconActive: "el-icon-warning",
          footerIconNormal: "el-icon-warning-outline"
        },
        {
          name: "考察船",
          mark: "004001001",
          pid: "observation-station",
          headerIconActive: "el-icon-user-solid",
          headerIconNormal: "el-icon-user",
          footerIconActive: "el-icon-warning",
          footerIconNormal: "el-icon-warning-outline",
          children: [
            {
              name: "雪龙2号",
              mark: "22cd30d7444f4f4399341ad5586768ed",
              pid: "004001001",
              headerIconActive: "el-icon-user-solid",
              headerIconNormal: "el-icon-user",
              footerIconActive: "el-icon-warning",
              footerIconNormal: "el-icon-warning-outline",
              children: [
                {
                  name: "船只介绍",
                  mark: "hhd81e26ha3h46d86cgd44e6f2bh93hc",
                  pid: "22cd30d7444f4f4399341ad5586768ed",
                  headerIconActive: "el-icon-user-solid",
                  headerIconNormal: "el-icon-user",
                  footerIconActive: "el-icon-warning",
                  footerIconNormal: "el-icon-warning-outline"
                },
                {
                  name: "建造过程",
                  mark: "ad18bf9f3g5bh8962d9e6g2ha1b1d219",
                  pid: "22cd30d7444f4f4399341ad5586768ed",
                  headerIconActive: "el-icon-user-solid",
                  headerIconNormal: "el-icon-user",
                  footerIconActive: "el-icon-warning",
                  footerIconNormal: "el-icon-warning-outline"
                },
                {
                  name: "船只特点",
                  mark: "4h4522d8f11b413cef3de47df139hd72",
                  pid: "22cd30d7444f4f4399341ad5586768ed",
                  headerIconActive: "el-icon-user-solid",
                  headerIconNormal: "el-icon-user",
                  footerIconActive: "el-icon-warning",
                  footerIconNormal: "el-icon-warning-outline"
                },
                {
                  name: "性能参数",
                  mark: "haf51b26932d2c727a9a9bba11c5cc16",
                  pid: "22cd30d7444f4f4399341ad5586768ed",
                  headerIconActive: "el-icon-user-solid",
                  headerIconNormal: "el-icon-user",
                  footerIconActive: "el-icon-warning",
                  footerIconNormal: "el-icon-warning-outline"
                },
                {
                  name: "性能参数",
                  mark: "ac142g16h7g942eafea65f54772dh7e3",
                  pid: "22cd30d7444f4f4399341ad5586768ed",
                  headerIconActive: "el-icon-user-solid",
                  headerIconNormal: "el-icon-user",
                  footerIconActive: "el-icon-warning",
                  footerIconNormal: "el-icon-warning-outline"
                },
                {
                  name: "船只功能",
                  mark: "23938776f74c7392cad6h4hg966b6712",
                  pid: "22cd30d7444f4f4399341ad5586768ed",
                  headerIconActive: "el-icon-user-solid",
                  headerIconNormal: "el-icon-user",
                  footerIconActive: "el-icon-warning",
                  footerIconNormal: "el-icon-warning-outline"
                },
                {
                  name: "船只设计",
                  mark: "ccchcc6b5c625fc24c1d68977ad3ahb7",
                  pid: "22cd30d7444f4f4399341ad5586768ed",
                  headerIconActive: "el-icon-user-solid",
                  headerIconNormal: "el-icon-user",
                  footerIconActive: "el-icon-warning",
                  footerIconNormal: "el-icon-warning-outline"
                },
                {
                  name: "航行试验",
                  mark: "ab228h99bg6d28274b13c183fab3ga5a",
                  pid: "22cd30d7444f4f4399341ad5586768ed",
                  headerIconActive: "el-icon-user-solid",
                  headerIconNormal: "el-icon-user",
                  footerIconActive: "el-icon-warning",
                  footerIconNormal: "el-icon-warning-outline"
                },
                {
                  name: "科学考察",
                  mark: "4b3bcahh85315b22a96d4edgbhdg4h44",
                  pid: "22cd30d7444f4f4399341ad5586768ed",
                  headerIconActive: "el-icon-user-solid",
                  headerIconNormal: "el-icon-user",
                  footerIconActive: "el-icon-warning",
                  footerIconNormal: "el-icon-warning-outline"
                },
                {
                  name: "最新消息",
                  mark: "f61fb214c833985a4fe527g8g9fc2517",
                  pid: "22cd30d7444f4f4399341ad5586768ed",
                  headerIconActive: "el-icon-user-solid",
                  headerIconNormal: "el-icon-user",
                  footerIconActive: "el-icon-warning",
                  footerIconNormal: "el-icon-warning-outline"
                },
                {
                  name: "建造意义",
                  mark: "bd9c153hbeead137g2f13636g77955d2",
                  pid: "22cd30d7444f4f4399341ad5586768ed",
                  headerIconActive: "el-icon-user-solid",
                  headerIconNormal: "el-icon-user",
                  footerIconActive: "el-icon-warning",
                  footerIconNormal: "el-icon-warning-outline"
                }
              ]
            },
            {
              name: "雪龙一号",
              mark: "4fd5c71775ef4cd78ef396049e7efb95",
              pid: "004001001",
              headerIconActive: "el-icon-user-solid",
              headerIconNormal: "el-icon-user",
              footerIconActive: "el-icon-warning",
              footerIconNormal: "el-icon-warning-outline"
            }
          ]
        },
        {
          name: "考察站",
          mark: "004001002",
          pid: "survey-ship",
          headerIconActive: "el-icon-user-solid",
          headerIconNormal: "el-icon-user",
          footerIconActive: "el-icon-warning",
          footerIconNormal: "el-icon-warning-outline",
          children: [
            {
              name: "罗斯海新站",
              mark: "011f3979b66b4b858d502b88a4e3125c",
              pid: "004001002",
              headerIconActive: "el-icon-user-solid",
              headerIconNormal: "el-icon-user",
              footerIconActive: "el-icon-warning",
              footerIconNormal: "el-icon-warning-outline",
              children: [
                {
                  name: "建设沿革",
                  mark: "44c1ec526gdf6878a8g29177bage43bh",
                  pid: "011f3979b66b4b858d502b88a4e3125c",
                  headerIconActive: "el-icon-user-solid",
                  headerIconNormal: "el-icon-user",
                  footerIconActive: "el-icon-warning",
                  footerIconNormal: "el-icon-warning-outline"
                },
                {
                  name: "地理位置",
                  mark: "7g1ce29315chcf9e7683ge829a9aah49",
                  pid: "011f3979b66b4b858d502b88a4e3125c",
                  headerIconActive: "el-icon-user-solid",
                  headerIconNormal: "el-icon-user",
                  footerIconActive: "el-icon-warning",
                  footerIconNormal: "el-icon-warning-outline"
                },
                {
                  name: "建设意义",
                  mark: "b9g3a2h619g26e7gb1f3dg614f27f2g8",
                  pid: "011f3979b66b4b858d502b88a4e3125c",
                  headerIconActive: "el-icon-user-solid",
                  headerIconNormal: "el-icon-user",
                  footerIconActive: "el-icon-warning",
                  footerIconNormal: "el-icon-warning-outline"
                },
                {
                  name: "建设历程",
                  mark: "34894b3e2g2g6adg6a55497g256g8ed4",
                  pid: "011f3979b66b4b858d502b88a4e3125c",
                  headerIconActive: "el-icon-user-solid",
                  headerIconNormal: "el-icon-user",
                  footerIconActive: "el-icon-warning",
                  footerIconNormal: "el-icon-warning-outline"
                },
                {
                  name: "站点工作",
                  mark: "6244f76be38fe16616adeah975e7hdb7",
                  pid: "011f3979b66b4b858d502b88a4e3125c",
                  headerIconActive: "el-icon-user-solid",
                  headerIconNormal: "el-icon-user",
                  footerIconActive: "el-icon-warning",
                  footerIconNormal: "el-icon-warning-outline"
                }
              ]
            },
            {
              name: "泰山站",
              mark: "ba5b63c95aa54bbebe90779b71864d28",
              pid: "004001002",
              headerIconActive: "el-icon-user-solid",
              headerIconNormal: "el-icon-user",
              footerIconActive: "el-icon-warning",
              footerIconNormal: "el-icon-warning-outline"
            },
            {
              name: "昆仑站",
              mark: "3e8edfc37af14496b5bcd48e098f0ac9",
              pid: "004001002",
              headerIconActive: "el-icon-user-solid",
              headerIconNormal: "el-icon-user",
              footerIconActive: "el-icon-warning",
              footerIconNormal: "el-icon-warning-outline"
            },
            {
              name: "黄河站",
              mark: "f530c149353a43cdbce1af2034cb25ed",
              pid: "004001002",
              headerIconActive: "el-icon-user-solid",
              headerIconNormal: "el-icon-user",
              footerIconActive: "el-icon-warning",
              footerIconNormal: "el-icon-warning-outline"
            },
            {
              name: "中山站",
              mark: "89c74e44d1c34b0b85791e6997e9f840",
              pid: "004001002",
              headerIconActive: "el-icon-user-solid",
              headerIconNormal: "el-icon-user",
              footerIconActive: "el-icon-warning",
              footerIconNormal: "el-icon-warning-outline"
            },
            {
              name: "长城站",
              mark: "cee27231146d40a293b6aac5226fa5fe",
              pid: "004001002",
              headerIconActive: "el-icon-user-solid",
              headerIconNormal: "el-icon-user",
              footerIconActive: "el-icon-warning",
              footerIconNormal: "el-icon-warning-outline"
            }
          ]
        }
      ]
   }, 2000);
  },
  methods: {
    selectItem(item) {
      console.log(item);
    }
  }
};
</script>

<style lang='scss'>

@import url("./assets/normalize.css");
ul{
  margin: 0;
  padding: 0;
  list-style: none;
}
</style>
  • .wrap.-recursion.vue文件
<template>
  <div class="wrapRecursion">
    <p class="wrapboxheaderstyle">
      <slot>目录树标题</slot>
    </p>
    <left-slide
      :menuarr="arr"
      :selectindex="flagIndex"
      :depth="depth"
      @selectitem="selectitem"
    ></left-slide>
  </div>
</template>
<script>
import recursion from "./recursion";
export default {
  name: "wrapRecursion",
  props: {
    menuarr: {
      type: Array,
      required: true
    },
    selectindex: {
      type: [String, Number],
      required: true
    },
    depth: {
      type: Number,
      default: 1.2
    },
    shiftIconBool: {
      type: Boolean,
      default: false
    }
  },
  data() {
    return {
      msg: "外包装递归组件",
      arr: [],
      flagIndex: ""
    };
  },
  components: {
    "left-slide": recursion
  },
  watch: {
    menuarr: {//实时监听异步返回来的数据
      handler(newName, oldName) {
        if (newName.length == this.menuarr.length) {
          this.arr = newName;
          this.flagIndex = this.selectindex;
          this.init(this.arr, this.flagIndex);
        }
      }
    }
  },
  created() {
    this.arr = this.menuarr;
    this.flagIndex = this.selectindex;
    this.init(this.arr, this.flagIndex);
  },
  methods: {
    addLock(arr) {//锁
      arr.forEach(item => { //工具函数-给数据数组中每一个对象都关锁
        this.$set(item, "lock", false);
        if (this.shiftIconBool) {//添加icon图标
          this.$set(item, "headerIcon", item.headerIconNormal||"el-icon-help");
          this.$set(item, "footerIcon", item.footerIconNormal||"el-icon-circle-plus-outline");
        }
        if (!!item.children) {
          this.addLock(item.children);
        }
      });
    },
    getParentNode(arr, mark, temp) {//工具函数-将数组中符合mark的对象放到一个新数组中
      for (var i = 0; i < arr.length; i++) {
        let item = arr[i];
        if (item.mark == mark) {
          temp.unshift(item);
          this.getParentNode(this.arr, item.pid, temp);
          break;
        } else {
          if (!!item.children) {
            this.getParentNode(item.children, mark, temp);
          }
        }
      }
      return temp;
    },
    init(arr, mark) {//初始化数据
      this.addLock(arr); //上锁
      this.getParentNode(arr, mark, []).forEach(item => {//部分开锁
        this.$set(item, "lock", true);
        if (this.shiftIconBool) {//添加icon图标
          this.$set(item, "headerIcon", item.headerIconActive||"el-icon-s-help");
          this.$set(item, "footerIcon", item.footerIconActive||"el-icon-remove");
        }
      });
    },
    selectitem(item) {
      if (item.mark == this.flagIndex) {//点击的是同一个item
        this.$set(item, "lock", !item.lock);
        if (this.shiftIconBool) {
          if (item.lock) {
            this.$set(item, "headerIcon", item.headerIconActive||"el-icon-s-help");
            this.$set(item, "footerIcon", item.footerIconActive||"el-icon-remove");
          } else {
            this.$set(item, "headerIcon", item.headerIconNormal||"el-icon-help");
            this.$set(item, "footerIcon", item.footerIconNormal||"el-icon-circle-plus-outline");
          }
        }
      } else {//点击的不是同一个item
        this.addLock(this.arr);//上锁
        this.getParentNode(this.arr, item.mark, []).forEach(item => {//部分开锁
          this.$set(item, "lock", true);
          if (this.shiftIconBool) {
            this.$set(item, "headerIcon", item.headerIconActive||"el-icon-s-help");
            this.$set(item, "footerIcon", item.footerIconActive||"el-icon-remove");
          }
        });
        this.getParentNode(this.arr, this.flagIndex, []).forEach(value => {//找到上一个选中的item关闭它
          if (value.mark == item.mark) {
            this.$set(item, "lock", false);
            if (this.shiftIconBool) {
              this.$set(item, "headerIcon", item.headerIconNormal||"el-icon-help");
              this.$set(item, "footerIcon", item.footerIconNormal||"el-icon-circle-plus-outline");
            }
          }
        });
      }
      this.flagIndex = item.mark;
      this.$emit("selectitem", item);
    }
  }
};
</script>
<style scoped src='./wrap-recursion.css'></style>//自定义的css样式(设置目录树的标题)
  • recursion.vue文件
  <template>
  <ul class="left-slide">
    <li
      v-for="(item,index) in menuarr"
      :key="index"
    >
      <p
        class="menuItem"
        :style="paddingLeft"
        :class="{active:item.mark==selectindex}"
        @click="selectitem(item)"
        :title="item.name"
      >
        <span :class="item.headerIcon"></span>
        <span>{{item.name}}</span>
        <span
          v-if="item.children"
          :class="item.footerIcon"
        ></span>
      </p>
      <el-collapse-transition>
        <left-slide
          v-if="item.children && item.lock"
          :menuarr="item.children"
          :selectindex="selectindex"
          @selectitem="selectitem"
          :depth="depth+1.5"
        ></left-slide>
      </el-collapse-transition>
    </li>
  </ul>
</template>

<style scoped lang='scss'>
.menuItem {//单号阶段
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
</style>

<style scoped src='./recursion.css'></style>//用户自定义目录树中每一项的样式

<script>
export default {
  name: "left-slide",
  props: {
    menuarr: {
      type: Array,
      required: true
    },
    selectindex: {
      type: [String, Number],
      required: true
    },
    depth: {
      type: Number,
      default: 0
    }
  },
  data() {
    return {
      msg: "左侧目录导航栏"
    };
  },
  created() {},
  computed: {
    paddingLeft() {
      return `padding-left: ${this.depth * 10}px`;
    }
  },
  mounted() {},
  methods: {
    selectitem(item) {
      //监听item的点击
      this.$emit("selectitem", item);
    }
  }
};
</script>