Vue--添加动画效果的树状递归展开组件

826 阅读1分钟

  前段时间要做一个树状递归的展开组件,原来都是用的第三方框架直接用,突然要用一个自定义能力比较强的,就想着看看有没有写的差不多的自己改一下得了,结果用某度搜了一下,清一色复制粘贴的文章,而且也写的极其简单。。。干脆还是自己撸得了。

效果图

2021-09-07 000848.gif

  不多说直接上代码吧。

如何引用组件

<template>
  <div style="width: 300px">
    <tree :treeArr="dataArr"></tree>
  </div>
</template>

<script>
import tree from "./tree.vue";
export default {
  components: {
    tree,
  },
  data() {
    return {
      dataArr: [],
    };
  },
  mounted() {
    this.dataArr = [
      {
        name: "广东",
        isShow: false,
        level: 1,
        children: [
          {
            name: "广州",
            isShow: false,
            level: 2,
            children: [
              {
                name: "天河区",
                level: 3,
                isShow: false,
                children: [],
              },
              {
                name: "黄埔区",
                level: 3,
                children: [],
              },
              {
                name: "荔湾区",
                level: 3,
                children: [],
              },
            ],
          },
          {
            name: "深圳",
            level: 2,
            isShow: false,
            children: [],
          },
          {
            name: "佛山",
            level: 2,
            isShow: false,
            children: [],
          },
        ],
      },
      {
        name: "湖北",
        isShow: false,
        level: 1,
        children: [
          {
            name: "武汉",
            level: 2,
            children: [],
          },
        ],
      },
    ];
  },
};
</script>

组件 tree

  • 组件中需要注意的几点:

    • v-show="item.children && item.children.length" 这个是递归组件的终止条件,如果没有停止条件就会陷入死循环,而且由于你会频繁的打开隐藏,所以就不要用v-if了,应该使用v-show;

    • 添加动画效果时,如果你的高度不确定,应该使用 max-height,但是数值不应该设置太大,否则会有很明显的卡顿效果,最好是估测一个和实际值差不多的高度,或者自行计算也可以。

<template>
  <div class="container" :style="{ 'max-height': isShow ? '500px' : 0 }">
    <div v-for="(item, index) in treeArr" :key="item.name">
      <div
        class="container-item"
        @click="handleOpenChildren(index)"
        :style="{transform: `translateX(${(item.level-1)*10}px)`}" //做一个偏移来显示层次
      >
        <img
          class="item-img"
          :src="
            item.isShow
              ? '../../../static/close.png'
              : '../../../static/open.png'
          "
        />
        <span>{{ item.name }}</span>
      </div>
      //递归组件的终止条件
      <div v-show="item.children && item.children.length">
        <tree :treeArr="item.children" :isShow="item.isShow"></tree>
      </div>
    </div>
  </div>
</template>

<script>
export default {
  name: "tree",  //递归组件的使用:定义name属性,就可以在当前文件中直接使用组件。(多提一句在uni-app中小程序使用递归组件还需要引用自己并在components中注册)
  props: {
    treeArr: Array,
    isShow: {
      type: Boolean,
      default: true,
    },
  },
  data() {
    return {
      arr: [],
    };
  },
  methods: {
    handleOpenChildren(index) {
      let data = this.treeArr[index];
      if (data.children && data.children.length) {
        data.isShow = !data.isShow;
      } else {
        // 如果数据特别多,使用了懒加载,此处需要请求接口添加数据
      }
    },
  },
};
</script>

<style>
.container {
  overflow: hidden;
  transition: 0.5s all;
}
.container-item {
  line-height: 30px;
  font-size: 15px;
  width: 100%;
  display: flex;
  flex-direction: row;
  align-items: center;
}

.item-img {
  height: 15px;
  width: 15px;
  margin: 0 20px;
}
</style>

  如果各位发现有什么错误和需要改进的地方还希望多多指出,谢谢各位