最近在做一个属于我内部的组件库,开发到了
collapse-transition
的时候,发现直接搬过来的动画实现不了,那可着急死我了,我因为我写错了,然后在代码里面去打断点,发现根本没有进入beforeEnter
里面,意思就是这个组件就没有生效,那么看看如何解决的
1、原因
问题出现在 el-collapse-transition 组件上,但是移植时代码已饿了么的源码一致,实现方式是通过vue的函数式组件的方式来实现的,对于函数式组件也不是很了解。多方查找原因,发现出在这个原来是ES6中class类的原型是不可以在vue中通过v-for遍历的。可以将ES6的class类的写法换成ES5的写法,ES5中class类的原型是可以进行遍历的。
new 出来的实例 的各种方法 是挂在新对象的原型上, 但是on 里面的函数必须是要在新对象本身上。
本着这个想法,看了饿了么npm包中transition文件夹下collapse-transition.js文件,果然写法转换为了ES5的写法。应该是饿了么发布npm时通过babel转换了写法。
2、解决TA
解决一:毫无疑问就是把打包后的代码弄过来
'use strict';
exports.__esModule = true;
var _dom = require('element-ui/lib/utils/dom');
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
var Transition = function () {
function Transition() {
_classCallCheck(this, Transition);
}
Transition.prototype.beforeEnter = function beforeEnter(el) {
(0, _dom.addClass)(el, '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;
};
Transition.prototype.enter = function 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';
};
Transition.prototype.afterEnter = function afterEnter(el) {
(0, _dom.removeClass)(el, 'collapse-transition');
el.style.height = '';
el.style.overflow = el.dataset.oldOverflow;
};
Transition.prototype.beforeLeave = function 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';
};
Transition.prototype.leave = function leave(el) {
if (el.scrollHeight !== 0) {
(0, _dom.addClass)(el, 'collapse-transition');
el.style.height = 0;
el.style.paddingTop = 0;
el.style.paddingBottom = 0;
}
};
Transition.prototype.afterLeave = function afterLeave(el) {
(0, _dom.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;
};
return Transition;
}();
exports.default = {
name: 'ElCollapseTransition',
functional: true,
render: function render(h, _ref) {
var children = _ref.children;
var data = {
on: new Transition()
};
return h('transition', data, children);
}
};
解法二
需要一定的ES5中class类的实现基础,将原来饿了么源码中的ES6写法仔细改写为ES5的class类实现,限于本人水平有限,放弃了这种方式o(╥﹏╥)o
解法三
把class直接改成ES常用的对象的方式,他们两种写法有一些不一样,也就是实例化上的差异,居然可以了解实例化的原理
import { addClass, removeClass } from 'main/utils/dom';
const Transition = {
beforeEnter(el) {
addClass(el, '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) {
// 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: function render(h, { children }) {
var data = {
on: Transition
};
return h('transition', data, children);
}
};
解法四
大家可以在Babel解析上去处理这个问题,时间问题,我没有去看,但是肯定是能处理的
3、el-collapse-transition
原理
其实原理挺有意思的,就是把transition
这个vue
标签进行一个封装,在他的钩子函数上进行了一些处理, 在进入和离开的钩子加上对应的动画去去掉
By: https://blog.csdn.net/weixin_43797046/article/details/114658599