概述
在日常实际开放当中,我们必不可少的会遇到树形结构的数据,然后根据数据,渲染出树形结构菜单,比如说后台管理系统的侧边栏和图书目录等等,我们一般遇到这种需求,一般会采用递归组件,渲染对应的树形结构。然后根据实际需求可以进行扩展,为了给用户更好的用户体验,如果给这种结构加上过渡动画,整个页面都会显得更加生动。以下是自定义封装的过渡动画组件。
组件代码
定义一个CommonCollapseTransition组件
<template>
<transition
v-on:before-enter="beforeEnter"
v-on:enter="enter"
v-on:after-enter="afterEnter"
v-on:before-leave="beforeLeave"
v-on:leave="leave"
v-on:after-leave="afterLeave"
>
<slot></slot>
</transition>
</template>
<script>
export default {
name: 'CommonCollapseTransition',
methods: {
beforeEnter(el) {
el.classList.add('collapse-transition');
if (!el.dataset) el.dataset = {};
el.dataset.oldPaddingTop = el.style.paddingTop;
el.dataset.oldPaddingBottom = el.style.paddingBottom;
el.style.height = '0';
el.style.paddingTop = 0;
el.style.paddingBottom = 0;
},
enter(el) {
el.dataset.oldOverflow = el.style.overflow;
if (el.scrollHeight !== 0) {
el.style.height = el.scrollHeight + 'px';
el.style.paddingTop = el.dataset.oldPaddingTop;
el.style.paddingBottom = el.dataset.oldPaddingBottom;
} else {
el.style.height = '';
el.style.paddingTop = el.dataset.oldPaddingTop;
el.style.paddingBottom = el.dataset.oldPaddingBottom;
}
el.style.overflow = 'hidden';
},
afterEnter(el) {
el.classList.remove('collapse-transition');
el.style.height = '';
el.style.overflow = el.dataset.oldOverflow;
},
beforeLeave(el) {
if (!el.dataset) el.dataset = {};
el.dataset.oldPaddingTop = el.style.paddingTop;
el.dataset.oldPaddingBottom = el.style.paddingBottom;
el.dataset.oldOverflow = el.style.overflow;
el.style.height = el.scrollHeight + 'px';
el.style.overflow = 'hidden';
},
leave(el) {
if (el.scrollHeight !== 0) {
el.classList.add('collapse-transition');
el.style.height = 0;
el.style.paddingTop = 0;
el.style.paddingBottom = 0;
}
},
afterLeave(el) {
el.classList.remove('collapse-transition');
el.style.height = '';
el.style.overflow = el.dataset.oldOverflow;
el.style.paddingTop = el.dataset.oldPaddingTop;
el.style.paddingBottom = el.dataset.oldPaddingBottom;
},
},
};
</script>
<style lang="less">
.collapse-transition {
transition: all 0.3s ease-in-out;
}
</style>
使用方法
谈到使用,我们首先应该构造一个树形结构菜单,这就需要用到递归组件,不知道啥是递归组件的,请移步到vue官方对递归组件的介绍
以下是一个递归组件目录树,数据采用mock模拟。
mock树形结构数据
export const previewBookInfoList = Mock.mock({
'data|15-40': [
{
Id: '@id()',
Title: '@ctitle()',
'readTime|5000-30000': 5000,
show: false,
active: false,
'children|4-10': [
{
Id: '@id()',
Title: '@ctitle()',
'readTime|500-5000': 200,
show: false,
active: false,
'children|4-10': [
{
Id: '@id()',
Title: '@ctitle()',
'readTime|500-5000': 200,
show: false,
active: false,
},
],
},
],
},
],
});
递归组件
<template>
<ul class="aside-bar" :style="{ paddingLeft: level * 12 + 'px' }">
<li v-for="(item, index) in list" :key="item.Id" :class="['catalog-level-' + level, 'catalog-item']">
<div class="content-wrap">
<span :class="['title', item.Id == currentActive ? 'active' : '']" @click.stop="getCalogBookList(item)"
>{{ item.Title }} {{ '(' + item.readTime + ')' }}</span
>
<span
class="catalog-fold icon"
v-if="item.children && item.children.length && !item.show"
@click.stop="openChild(item)"
></span>
<span
class="catalog-unfold icon"
@click.stop="openChild(item)"
v-if="item.show && item.children && item.children.length && item.show"
></span>
</div>
<!-- S 递归组件 ,在这里使用过渡组件-->
<common-collapse-transition>
<aside-bar
:level="level + 1"
:list="item.children"
v-if="item.children && item.children.length && item.show"
:currentActive="currentActive"
@getCalogBookList="getCalogBookList"
></aside-bar>
</common-collapse-transition>
<!-- E 递归组件,在这里使用过渡组件 -->
</li>
</ul>
</template>
<script>
export default {
name: 'AsideBar',
components: {},
props: {
level: {
type: Number,
default: 1,
},
list: {
type: Array,
default() {
return [];
},
},
currentActive: {
type: String,
default: '-1',
},
},
data() {
return {};
},
methods: {
openChild(item) {
item.show = !item.show;
},
getCalogBookList(item) {
console.log(item);
if (item.Id == this.currentActive) return;
this.$emit('getCalogBookList', item);
},
},
};
</script>
<style lang="less">
.aside-bar {
font-size: 12px;
line-height: 38px;
.catalog-level-1 {
color: #333;
}
.catalog-item {
transition: color 0.3s;
cursor: pointer;
.title {
&:hover {
color: #1a73c5;
font-weight: bold;
}
}
.title.active {
color: #1a73c5;
font-weight: bold;
}
}
.content-wrap {
position: relative;
padding-left: 20px;
}
.icon {
position: absolute;
left: 0;
top: 50%;
transform: translate(0, -50%);
width: 11px;
height: 11px;
background-repeat: no-repeat;
}
.catalog-fold {
background-image: url('../../assets/images/partnerSchool/catalog-fold.png');
}
.catalog-unfold {
background-image: url('../../assets/images/partnerSchool/catalog-unfold.png');
}
}
</style>
效果
总结
以上知识需要首先掌握递归组件,其次需要对dom元素的尺寸获取设置要知道,上面的看懂了,日常工作中的树形结构渲染,都基本上一个思路,递归很重要