vue 树形目录结构

 原先使用的是Ztree,后来因为更多的定制化要求,还是手写一个算了

<template>
  <div>
    <menu-tree :nodes="nodes" :selected="currentCameraId"></menu-tree>
  </div>
</template>

<script>

  import EventBus from "@/utils/EventBus";
  import MenuTree from "@/views/HomePage2D/components/MenuTree";
  import dh_config from "static/config/dh-camera";

  export default {
    name: "zoneDeviceDir",
    components: {MenuTree},
    data() {
      return {
        nodes: [],
        allNodes: [],
        currentCameraId: ''
      }
    },
    watch: {},
    computed: {},
    methods: {
      //选中
      cameraClick(item) {
        this.currentCameraId = this.currentCameraId === item.id ? '' : item.id;
        if (this.currentCameraId !== '') {
          EventBus.$emit('showThisVideo',item)
        }
      },
      //全部展开或折叠
      allNoExpand(flag) {
        this.nodes.forEach(node => {
          this.noExpand(node, flag)
        })
      },
      noExpand(node, flag) {
        node.expand = flag;
        if (node.children && node.children.length > 0) {
          node.children.forEach(childNode => {
            this.noExpand(childNode, flag)
          })
        }
      },
      //反向定位
      reverseCamera(id) {


        this.currentCameraId = id;
        this.allNoExpand(false);
        this.nodes = this.allNodes;
        this.cameraSelect(this.nodes, id);
      },
      cameraSelect(nodes, queryData) {
        for (let i = 0; i < nodes.length; i++) {
          let node = nodes[i];
          if (node.children === null && this.corCamera(node, queryData)) {
            node.expand = true;
          } else {
            let deepQuery = this.corCamera(node, queryData);
            if (deepQuery) {
              node.expand = true;
              if (node.children) {
                this.cameraSelect(node.children, queryData);
              }
            }
          }
        }
      },
      corCamera(node, queryData) {
        if (node.children === null) {
          if (node.id === queryData) {
            return true;
          } else {
            return false;
          }
        }
        for (let i = 0; i < node.children.length; i++) {
          if (this.corCamera(node.children[i], queryData)) {
            return true;
          }
        }
        return false;
      },
      //查找
      search(queryData) {
        let array = this.treeSelect(this.allNodes, queryData);
        this.nodes = array;
        this.allNoExpand(true);
      },
      treeSelect(nodes, queryData) {
        let newArray = [];
        for (let i = 0; i < nodes.length; i++) {
          let node = nodes[i];
          if (node.children === null && this.treeDeepQuery(node, queryData)) {
            newArray.push(node);
          } else {

            let deepQuery = this.treeDeepQuery(node, queryData);
            if (deepQuery) {
              let newNode = JSON.parse(JSON.stringify(node));
              if (node.children) {
                newNode.children = this.treeSelect(node.children, queryData);
              }
              newArray.push(newNode)
            }
          }

        }
        return newArray;
      },
      treeDeepQuery(node, queryData) {
        if (node.children === null) {
          if (node.name.indexOf(queryData) !== -1) {
            return true;
          } else {
            return false;
          }
        }

        for (let i = 0; i < node.children.length; i++) {
          if (this.treeDeepQuery(node.children[i], queryData)) {
            return true;
          }
        }
        return false;
      }
    },
    mounted() {
      EventBus.$on("item-click", this.cameraClick)
      EventBus.$on('ReversePositioning',this.reverseCamera)
      let T = this
      this.$axios.get(`/camera/menu/list?&time=${new Date().getTime()}`).then(res => {
        if (res.data.code !== 200) {
          this.$Message.error(res.data.msg)
        } else {
          T.nodes = res.data.data
          T.allNodes = res.data.data
        }
      })
    },
    beforeDestroy() {
    }
  }
</script>

<style lang="scss" scoped>
</style>

树组件

<template>
  <div class="menu-tree" :class="{'menu-tree-top' : top}">
    <div v-for="item in nodes" :key="item.id">
      <!--菜单-->
      <div class="menu-item" @click="folderClick(item)" v-show="item.children !== null && item.num > 0">
        <div style="position: absolute;top: 0;left: 20px;width: calc(100% - 20px);height: 100%"></div>
          <i class="iconfont iconjia" v-show="!item.expand" style="color: #0ABBE5"></i>
          <i class="iconfont iconjian" v-show="item.expand"></i>
          {{item.name}}<span v-show="item.num > 0">({{item.num}})</span>
      </div>
      <!--摄像头-->
      <div class="menu-item" @click="itemClick(item)" v-show="item.children === null"  :class="{'menu-item-selected-parent':item.id === selected}">
        <div style="position: absolute;top: 0;left: 20px;width: calc(100% - 20px);height: 100%" :class="{'menu-item-selected':item.id === selected}"></div>
        <i class="iconfont iconshexiangtou" :class="[{'online': item.statusName === '在线'},{'offline': item.statusName !== '在线'}]"></i>
        <span>({{item.resource}})&nbsp;</span>{{item.name}}
      </div>
      <!--子菜单递归-->
      <div v-show="item.children && item.children.length > 0 && item.expand" class="child-menu">
        <menu-tree :nodes="item.children" :selected="selected" :top="false"></menu-tree>
      </div>
    </div>
  </div>
</template>

<script>
  import EventBus from "@/utils/EventBus";

  export default {
    props: {
      nodes: Array,
      selected: String,
      top: {
        required: false,
        default: true
      }
    },
    name: "MenuTree",
    data() {
      return {}
    },
    mounted() {
    },
    methods: {
      itemClick(item) {
        EventBus.$emit('item-click', item);
      },
      folderClick(item) {
        this.nodes.forEach(node => {
          if (node.id === item.id) {
            node.expand = !node.expand;
          }
        })
      }
    }
  }
</script>

<style lang="scss">

  .menu-tree {
    color: #333;
    font-size: 17px;
    position: relative;

    .menu-item {
      position: relative;
      padding-left: 25px;
      height: 40px;
      line-height: 40px;
      overflow: hidden;
      text-overflow: ellipsis;
      white-space: nowrap;


      .online {
        color: #1686D8;
      }

      .offline {
        color: #B7C3CE;
      }

      .menu-item-selected {
        border: 1px solid #1686D8;
        background: rgba(22, 134, 216, 0.1);
      }


      &:hover {
        cursor: pointer;
        > div {
          &:first-child {
            border: 1px solid #1686D8;
            background: rgba(22, 134, 216, 0.1);
          }
        }
      }

      &:after {
        content: "";
        width: 11px;
        height: 20px;
        position: absolute;
        left: 12px;
        top: 19px;
        border-width: 1px;
        border-top: 1px dashed #52627C;
      }
    }

    .menu-item-selected-parent {
      font-weight: bold;
    }

    .menu-item-camera {
      width: 100%;
    }

    .child-menu {
      margin-left: 20px;
      position: relative;
      &:before {
        content: "";
        height: calc(100% - 11px);
        width: 1px;
        position: absolute;
        left: 12px;
        top: -11px;
        border-width: 1px;
        border-left: 1px dashed #52627C;
      }
    }
  }

  .menu-tree-top > div > .menu-item {
    /*padding-left: 0;*/
    &:before {
      border-left: none;
    }
    &:after {
      border-top: none;
    }
  }
</style>
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值