JavaScript

超轻量级php框架startmvc

vue递归组件实战之简单树形控件实例代码

更新时间:2020-09-09 19:54:01 作者:startmvc
1、递归组件-简单树形控件预览及问题 在编写树形组件时遇到的问题:组件如何才能递

1、递归组件-简单树形控件预览及问题

 

在编写树形组件时遇到的问题:

  • 组件如何才能递归调用?
  • 递归组件点击事件如何传递?

2、树形控件基本结构及样式


<template>
 <ul class="vue-tree">
 <li class="tree-item">
 <div class="tree-content"><!--节点内容-->
 <div class="expand-arrow"></div><!--展开或收缩节点按钮-->
 <div class="tree-label">小学</div><!--节点文本内容-->
 </div>
 <ul class="sub-tree"><!--子节点-->
 <li class="tree-item expand">
 <div class="tree-content">
 <div class="expand-arrow"></div>
 <div class="tree-label">语文</div>
 </div>
 </li>
 <li class="tree-item">
 <div class="tree-content">
 <div class="expand-arrow"></div>
 <div class="tree-label">数学</div>
 </div>
 </li>
 </ul>
 </li>
 </ul>
</template>

<style lang="stylus">
.vue-tree{
 list-style: none;
 padding: 0;
 margin: 0;
 .tree-item{
 cursor: pointer;
 transition: background-color .2s;
 .tree-content{
 position: relative;
 padding-left: 28px;
 &:hover{
 background-color: #f0f7ff;
 }
 }
 .expand-arrow{
 position: absolute;
 top: 0;
 left: 0;
 width: 28px;
 height: 28px;
 cursor: pointer;
 &::after{
 position: absolute;
 top: 50%;
 left: 50%;
 display: block;
 content: ' ';
 border-width: 5px;
 border-style: solid;
 border-color: transparent;
 border-left-color: #ccc;
 margin: -5px 0 0 -2.5px;
 transition: all .2s;
 }
 }
 &.expand{
 &>.tree-content{
 background-color: #f0f7ff;
 &>.expand-arrow{
 &::after{
 transform: rotate(90deg);
 margin: -2.5px 0 0 -5px;
 }
 }
 }
 }
 .tree-label{
 height: 28px;
 line-height: 28px;
 font-size: 14px;
 }
 .sub-tree{
 display: none;
 list-style: none;
 padding: 0 0 0 28px;
 margin: 0;
 }
 &.expand>.sub-tree{
 display: block;
 }
 &.no-child{
 &>.tree-content{
 &>.expand-arrow{
 display: none;
 }
 }
 }
 }
}
</style>

3、组件目录及数据结构

目录结构

vue-tree

VueTree.vue TreeItem.vue

树形控件数据结构


let treeData = [
 {
 text: "一级", // 显示的文字
 expand: false, // 默认是否展开
 children: [ // 子节点
 {
 text: "一级-1",
 expand: false,
 },
 {
 text: "一级-2",
 expand: false,
 children: [
 {
 text: "一级-2-1",
 expand: false,
 },
 {
 text: "一级-2-2",
 expand: false,
 }
 ]
 }
 ]
 }
];

3.1、 TreeItem.vue 代码


<template>
 <li class="tree-item" :class="{expand: isExpand, 'no-child': !treeItemData.children || treeItemData.children.length === 0}">
 <div class="tree-content" @click="_clickEvent">
 <div class="expand-arrow" @click.stop="expandTree()"></div>
 <div class="tree-label">{{treeItemData.text}}</div>
 </div>
 <ul class="sub-tree" v-if="treeItemData.children && treeItemData.children.length > 0">
 <!--TreeItem组件中调用TreeItem组件-->
 <TreeItem
 v-for="item in treeItemData.children"
 :tree-item-data="item"
 :key="uuid()"
 :tree-click-event="treeClickEvent"></TreeItem>
 </ul>
 </li>
</template>

<script>
 export default {
 name: "TreeItem",
 props: {
 treeItemData: {
 type: Object,
 default(){
 return {};
 }
 },
 // 节点点击事件
 treeClickEvent: {
 type: Function,
 default() {
 return function () {};
 }
 }
 },
 data(){
 return {
 // 节点是否展开
 isExpand: this.treeItemData.expand || false
 }
 },
 methods: {
 // 展开/收缩
 expandTree(flag){
 if(!this.treeItemData.children || this.treeItemData.children.length === 0){
 return;
 }
 if(typeof flag === 'undefined'){
 flag = !this.isExpand;
 }else{

 flag = !!flag;
 }
 this.isExpand = flag;
 },
 // 创建一个唯一id
 uuid(){
 let str = Math.random().toString(32);
 str = str.substr(2);
 return str;
 },
 // 节点点击事件
 _clickEvent(){
 // 如果有传递事件函数,则调用事件函数并传递当前节点数据及组件
 if(this.treeClickEvent && typeof this.treeClickEvent === 'function'){
 this.treeClickEvent(this.treeItemData, this);
 }
 }
 }
 }
</script>

3.1.1、解决 组件如何才能递归调用? 问题

在组件模板内调用自身 必须明确定义组件的name属性 ,并且递归调用时组件名称就是name属性。如在 TreeItem.vue 组件中组件的name名称为'TreeItem',那么在template中调用时组件名称就必须是 <TreeItem> 。

当然也可以全局注册组件,具体可以查看vue官方文档 递归组件

3.1.2、解决 递归组件点击事件如何传递? 问题

我这里的解决方案是使用 props 将事件函数传递进来,在点击节点的时候调用事件函数,并把相应的数据传递进去。

之前也尝试过使用 $emit 的形式并把数据传递过去,由于是递归组件,这样一直 $emit ,到最外层时传递的数据就变了,比如传递是第3层节点的数据,到最后执行时数据就变成第1层节点的数据了

4、 VueTree.vue 组件


<template>
 <ul class="vue-tree">
 <TreeItem
 v-for="(item, index) in treeData"
 :key="index"
 :treeItemData="item"
 :tree-click-event="treeClickEvent"></TreeItem>
 </ul>
</template>

<script>
 import TreeItem from "./TreeItem";
 export default {
 name: "VueTreeMenu",
 components: {
 TreeItem
 },
 props: {
 // 树形控件数据
 treeData: {
 type: Array,
 default(){
 return [];
 }
 },
 // 节点点击事件
 treeClickEvent: {
 type: Function,
 default() {
 return function () {};
 }
 }
 }
 }
</script>

<style lang="stylus">
.vue-tree{
 list-style: none;
 padding: 0;
 margin: 0;
 .tree-item{
 cursor: pointer;
 transition: background-color .2s;
 .tree-content{
 position: relative;
 padding-left: 28px;
 &:hover{
 background-color: #f0f7ff;
 }
 }
 .expand-arrow{
 position: absolute;
 top: 0;
 left: 0;
 width: 28px;
 height: 28px;
 cursor: pointer;
 &::after{
 position: absolute;
 top: 50%;
 left: 50%;
 display: block;
 content: ' ';
 border-width: 5px;
 border-style: solid;
 border-color: transparent;
 border-left-color: #ccc;
 margin: -5px 0 0 -2.5px;
 transition: all .2s;
 }
 }
 &.expand{
 &>.tree-content{
 background-color: #f0f7ff;
 &>.expand-arrow{
 &::after{
 transform: rotate(90deg);
 margin: -2.5px 0 0 -5px;
 }
 }
 }
 }
 .tree-label{
 height: 28px;
 line-height: 28px;
 font-size: 14px;
 }
 .sub-tree{
 display: none;
 list-style: none;
 padding: 0 0 0 28px;
 margin: 0;
 }
 &.expand>.sub-tree{
 display: block;
 }
 &.no-child{
 &>.tree-content{
 /*padding-left: 0;*/
 &>.expand-arrow{
 display: none;
 }
 }
 }
 }
}
</style>

5、使用树形组件


<template>
 <div class="app" id="app">
 <VueTree :tree-data="treeData2" :tree-click-event="treeClickEvent"></VueTree>
 </div>
</template>

<script>
import VueTree from "./components/vue-tree/VueTree";

export default {
 name: 'app',
 data(){
 return {
 treeData2: [
 {
 text: "一级", // 显示的文字
 expand: false, // 默认是否展开
 children: [
 {
 text: "二级-1",
 expand: false,
 },
 {
 text: "二级-2",
 expand: false,
 children: [
 {
 text: "三级-1",
 expand: false,
 },
 {
 text: "三级-2",
 expand: false,
 children: [
 {
 text: "四级-1",
 expand: false,
 }
 ]
 }
 ]
 }
 ]
 },
 {
 text: "一级-2",
 expand: false
 }
 ]
 }
 },
 methods: {
 treeClickEvent(item, treeItem){
 console.log(item);
 }
 },
 components: {
 VueTree
 }
}
</script>

总结

以上所述是小编给大家介绍的vue递归组件实战之简单树形控件实例代码,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对脚本之家网站的支持! 如果你觉得本文对你有帮助,欢迎转载,烦请注明出处,谢谢!

vue递归组件 vue 树形控件