子菜单的展开、收缩功能在许多系统上都很常见,如果想要在打开收起时带有动画效果,过去常常会通过 jQuery 实现。而在 Vue 项目中,我们可以单独封装一个动画组件,方便使用。
1,效果图
点击一级菜单时,子菜单会从上往下逐渐展开。
再次点击一级菜单,子菜单又会从下往上收起。
2,创建动画组件(collapseTransition.js)
组件代码如下,其内容是通过 overflow 获取高度的方法创建了一个函数式组件实现展开、收起的动画效果。
/* 视图伸缩动画效果组件 */
/* jshint esversion: 6 */
const elTransition = '0.3s height ease-in-out, 0.3s padding-top ease-in-out, 0.3s padding-bottom ease-in-out';
const Transition = {
'before-enter' (el) {
el.style.transition = elTransition;
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';
},
'after-enter' (el) {
el.style.transition = '';
el.style.height = '';
el.style.overflow = el.dataset.oldOverflow;
},
'before-leave' (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.style.transition = elTransition;
el.style.height = 0;
el.style.paddingTop = 0;
el.style.paddingBottom = 0;
}
},
'after-leave' (el) {
el.style.transition = '';
el.style.height = '';
el.style.overflow = el.dataset.oldOverflow;
el.style.paddingTop = el.dataset.oldPaddingTop;
el.style.paddingBottom = el.dataset.oldPaddingBottom;
}
};
export default {
name: 'collapseTransition',
functional: true,
render (h, { children }) {
const data = {
on: Transition
};
return h('transition', data, children);
}
};
3,使用样例
使用时我们只需引入这个动画组件,包裹在需要显示、隐藏的元素外部即可(不再需要 css 与其它逻辑)
import axios from 'axios'
// 引入伸缩效果组件
import collapseTransition from './collapseTransition'
export default {
data () {
return {
isActive:false,
menus:[{
"title": "终端",
"icon": "/static/images/icon_1.png",
"isExpand": true,
"children": [{
"title": "智能物联网边缘计算"
}, {
"title": "终端融合能力"
}]
}, {
"title": "网络",
"icon": "/static/images/icon_2.png",
"isExpand": true,
"children": [{
"title": "客户侧内部组织网"
}]
}]
}
},
components: {
collapseTransition
},
methods:{
//展开收起按钮点击
changeExpand(menu) {
menu.isExpand = !menu.isExpand;
console.log(menu.isExpand);
}
}
}
#navigation {
background-color: #e7e7e7;
}
.menu-item {
width: 327px;
height: 49px;
line-height: 49px;
font-size: 14px;
border-bottom: solid 1px #c4c4c4;
color: #3d3d3d;
cursor:pointer;
}
.first-level {
background: url(../assets/images/first_level_menu_bg.png);
font-weight: bold;
}
.first-level img:first-child {
vertical-align:middle;
margin-left: 20px;
margin-right: 15px;
}
.first-level span {
width: 230px;
display: inline-block;
}
.second-level {
width: 320px;
border-left: solid 7px #e7e7e7;
}
.second-level:hover {
background-color: #ffffff;
color: #13a3a9;
border-left: solid 7px #f6ab36;
}
.second-level img:first-child {
vertical-align:middle;
margin-left: 61px;
margin-right: 10px;
}