用Vue实现一个最简单的树形组件

10 篇文章 0 订阅

一个简洁的树形组件实现,作为一个练手。
效果图

index.html
<!DOCTYPE html>
<html>
<head>
  <meta http-equiv="content-type" content="text/html; charset=utf-8" />
  <title>树形组件</title>
  <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/font-awesome/4.7.0/css/font-awesome.min.css">
  <link rel="stylesheet" href="https://unpkg.com/element-ui/lib/theme-chalk/index.css">
  <link rel="stylesheet" type="text/css" href = "./index.css" />
  <style type="text/css"></style>
  <script src="https://cdn.staticfile.org/jquery/1.10.2/jquery.min.js"></script>
  <script src="https://cdn.staticfile.org/vue/2.5.2/vue.min.js"></script>
  <script src="https://unpkg.com/element-ui/lib/index.js"></script>
</head>
<body>
  <template id="tree">
    <ul class="ul-wrapper">
      <li v-for="(item,idx) in list" :key="idx">
        <div class="tree-node-content" @click="updateExpand(item)">
          <icon :style="{opacity: item.children ? 1 : 0}" :class="['el-icon','el-icon-caret-right',item.expanded ? 'caret-down' : '']"></icon>
          <el-checkbox
            v-model="item.choosed"
            @change="chooseChildren(item)"></el-checkbox>
          <span class="label">{{ item.label }}</span>
        </div>
        <transition name="tree-show">
          <tree v-show="item.expanded" v-if="item.children" :list="item.children"></tree>
        </transition>
      </li>
    </ul>
  </template>
  <main id="app" class="container">
    <tree :list="dat"></tree>
  </main>
  <script src="./index.js"></script>
</body>
</html>

这里用到el-icon,是一个箭头,用.caret-down控制箭头向右or向下。

index.css
/* 参考:
https://element.eleme.cn/#/zh-CN/component/tree
https://cn.vuejs.org/v2/guide/transitions.html#%E8%BF%87%E6%B8%A1%E6%A8%A1%E5%BC%8F
*/
body{
  margin: 0;
}

ul{
  list-style-type: none;
}

.container{
  width: 100%;
  height: 100vh;
  display: grid;
  place-items: center;
}

.ul-wrapper{
  background-color: white;
  user-select: none;
  color: #606266;
  font-size: 14px;
  padding-left: 16px;
}

.tree-node-content{
  cursor: pointer;
  padding: 4px 0;
}

.ul-wrapper .tree-node-content:hover{
  background-color: #f5f7fa;
}

.tree-node-content icon{
  transition: all .5s;
}

icon.caret-down{
  transform: rotate(90deg);
}

.tree-show-enter-active, .tree-show-leave-active {
  transition: opacity .5s;
}

.tree-show-enter-to, .tree-show-leave-to {
  opacity: 0;
}

貌似都很显然,没啥说的。

index.js
"use strict";

function main() {
  Vue.component('tree', {
    props: {
      list: Array
    },
    created() {
      this.list.forEach(item => {
        this.$set(item, 'expanded', false)
        this.$set(item, 'choosed', false)
        return item
      })
    },
    methods: {
      updateExpand(item) {
        item.expanded = !item.expanded
      },
      chooseChildren(item, val = false, dep = 0) {
        if (dep) {
          item.choosed = val
        } else {
          val = item.choosed//根节点已更改过
        }
        if (!item.hasOwnProperty('children')) return
        for (let ch of item.children) {
          this.chooseChildren(ch, val, dep + 1)
        }
      }
    },
    template: '#tree'
  })
  let vm = new Vue({
    el: '#app',
    data() {
      return {
        dat: [{
          label: '一级 1',
          children: [{
            label: '二级 1-1',
            children: [{
              label: '三级 1-1-1'
            }]
          }]
        }, {
          label: '一级 2',
          children: [{
            label: '二级 2-1',
            children: [{
              label: '三级 2-1-1'
            }]
          }, {
            label: '二级 2-2',
            children: [{
              label: '三级 2-2-1'
            }]
          }]
        }, {
          label: '一级 3',
          children: [{
            label: '二级 3-1',
            children: [{
              label: '三级 3-1-1'
            }]
          }, {
            label: '二级 3-2',
            children: [{
              label: '三级 3-2-1'
            },{
              label: '三级 3-2-2'
            }]
          }]
        }]
      }
    },
    methods: {}
  });
}

$(document).ready(main);

组件在created这个生命周期插入两条新属性,expanded表示是否展开children,choosed表示是否选中(规定所有后代的选中状态应等于当前节点的)。在created时插入,这样插入新属性的代码就只会在组件创建的时候执行。

chooseChildren就是一个dfs,更新所有后代的选中状态。值得注意的是,被点击的那个节点已经修改为最新了。我们用深度==0判定是不是根,是根就获取所有后代应取的共同值,否则进行赋值。

  • 2
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值