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

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递归组件实战之简单树形控件实例代码 的全部内容, 来源链接: utcz.com/z/328378.html

回到顶部