- element 提供了三种动画方式 官网对应链接
- fade 淡入淡出
- zoom 缩放
- collapse 展开折叠( el-collapse-transition )
- vue官网关于transition过渡说明
此处仅解析collapse 展开折叠的实现
-
element 通过构造一个Transition类对象 设置了VUE内置transition组件对应的js钩子函数
-
通过render方法 返回一个Vue内置的transition组件并通过on:new transition()的形式构造一个动画类绑定对应事件函数
-
element自定义的过渡组件 组件名称为ElCollapseTransition
-
关于组件配置了name属性 对应官方文档 类名替换规则
-
关于类名及js钩子的执行时机官方说明 (总结:恰当时机)
源码
element ui 通过 jsx 语法实现源码
没有什么好备注的 思路很清晰
class Transition {
beforeEnter(el) {
addClass(el, 'collapse-transition');
// js原生dom添加类名方法
// document.querySelector('.class').classList.add('collapse-transition')
// document.querySelector('.class').classList.remove('collapse-transition')
if (!el.dataset) el.dataset = {};
// 将dom上的style设置的padding样式存起来 后面设置dom出现的时候用
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) {
// for safari: remove class then reset height is necessary
removeClass(el, '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) {
// for safari: add class after set height, or it will jump to zero height suddenly, weired
addClass(el, 'collapse-transition');
el.style.height = 0;
el.style.paddingTop = 0;
el.style.paddingBottom = 0;
}
}
afterLeave(el) {
removeClass(el, 'collapse-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: 'ElCollapseTransition',
functional: true,
render(h, { children }) {
const data = {
on: new Transition()
};
// 声明了组件的
return h('transition', data, children);
}
};
对应的css
根据不同的动画方式 设置专门的动画类 这里只写一种 el-zoom-in-top(往上缩放)
其他效果(往左、往右、往下、中间)通过改变 transform-origin 值 即可 不做解释
// 设置动画时间、动画属性
.collapse-transition {
transition: 0.3s height ease-in-out, 0.3s padding-top ease-in-out, 0.3s padding-bottom ease-in-out;
}
.el-zoom-in-top-enter-active,
.el-zoom-in-top-leave-active {
opacity: 1;
transform: scaleY(1);
transition: 0.3s;
transform-origin: center top;
}
.el-zoom-in-top-enter,
.el-zoom-in-top-leave-active {
opacity: 0;
transform: scaleY(0);
}
动画通过原生js实现思路
- 出现之前 beforeEnter
- 给dom节点上加 .collapse-transition 类名( 设置参与动画的属性和动画时间 不论何种动画方式都要设置这个所以单独抽离出来一个类名公用了-----我推测的 )
- 给dom节点添加上 el-zoom-in-top-enter 出现前样式(设置元素"opacity:0")。注:不设置为零 即使设置了外层div高度为0,但内部元素仍然会显现 但不占据页面高度会和下面的元素重叠
- 通过scrollHeight获取dom元素的高度
- 通过dom.style.paddingTop、style.paddingBottom获取元素的行内样式上的padding值
- 在原生节点上设置dataset对象。将刚获取的数据存起来
- 然后通过 el.style.height、style.paddingTop、style.paddingBottom 将元素的高、内边距设置为零
- 出现时 enter
- 将节点的 overflow 属性值保存起来 dom.dataset.oldOverflow = dom.style.overflow;
- 将存在dataset中的节点的 高和padding恢复
- 设置节点的overflow值为hidden
- 出现后 afterEnter
- 移除出现前设置的 .collapse-transition 类名
- 设置 el.style.height = ''; 行内样式就不会有 出现时 设置的height高数据了
- 出现时更改了overflow值 改回去
// js原生dom添加类名方法
// document.querySelector('.class').classList.add('collapse-transition')
// document.querySelector('.class').classList.remove('collapse-transition')