之前封装手风琴的时候借鉴列element做了个collapse折叠板动画。
网上有个大神也做了个collapse折叠板动画。传送门这里赞最多的就是element的那个动画。
我的那个element动画也是这个,vue 自定义指令封装一个手风琴嵌套组件这里的组件过度动画
但是这个动画并不支持设置时间,进一步封装还是可以的。
重写了一个collapse 的动画。
效果如下
新建collapseMixins.js,内容如下
export default {
inheritAttrs: false,
props: {
duration: {
type: [Number, Object],
default: 300
},
delay: {
type: [Number, Object],
default: 0
},
group: Boolean,
tag: {
type: String,
default: "span"
},
origin: {
type: String,
default: ""
},
styles: {
type: Object,
default: () => {
return {
animationFillMode: "both",
animationTimingFunction: "ease-out"
};
}
}
},
computed: {
componentType() {
return this.group ? "transition-group" : "transition";
},
hooks() {
return {
...this.$listeners,
beforeEnter: this.beforeEnter,
afterEnter: el => {
this.cleanUpStyles(el);
this.$emit("after-enter", el);
},
beforeLeave: this.beforeLeave,
leave: this.leave,
afterLeave: el => {
this.cleanUpStyles(el);
this.$emit("after-leave", el);
}
};
}
},
methods: {
beforeEnter(el) {
let enterDuration = this.duration.enter
? this.duration.enter
: this.duration;
el.style.animationDuration = `${enterDuration}ms`;
let enterDelay = this.delay.enter ? this.delay.enter : this.delay;
el.style.animationDelay = `${enterDelay}ms`;
this.setStyles(el);
this.$emit("before-enter", el);
},
cleanUpStyles(el) {
Object.keys(this.styles).forEach(key => {
const styleValue = this.styles[key];
if (styleValue) {
el.style[key] = "";
}
});
el.style.animationDuration = "";
el.style.animationDelay = "";
},
beforeLeave(el) {
let leaveDuration = this.duration.leave
? this.duration.leave
: this.duration;
el.style.animationDuration = `${leaveDuration}ms`;
let leaveDelay = this.delay.leave ? this.delay.leave : this.delay;
el.style.animationDelay = `${leaveDelay}ms`;
this.setStyles(el);
this.$emit("before-leave", el);
},
leave(el, done) {
this.setAbsolutePosition(el);
this.$emit("leave", el, done);
},
setStyles(el) {
this.setTransformOrigin(el);
Object.keys(this.styles).forEach(key => {
const styleValue = this.styles[key];
if (styleValue) {
el.style[key] = styleValue;
}
});
},
setAbsolutePosition(el) {
if (this.group) {
el.style.position = "absolute";
}
return this;
},
setTransformOrigin(el) {
if (this.origin) {
el.style.transformOrigin = this.origin;
}
return this;
}
}
};
建立一个collapseTransition.js,内容如下
import Vue from "../utils/vue";
import collapseMixins from "./collapseMixins";
const name = "NlyCollapseTransition";
export const NlyCollapseTransition = Vue.extend({
name: name,
mixins: [collapseMixins],
methods: {
transitionStyle(duration = 300) {
let durationInSeconds = duration / 1000;
let style = `${durationInSeconds}s height ease-in-out, ${durationInSeconds}s padding-top ease-in-out, ${durationInSeconds}s padding-bottom ease-in-out`;
return style;
},
beforeEnter(el) {
let enterDuration = this.duration.enter
? this.duration.enter
: this.duration;
el.style.transition = this.transitionStyle(enterDuration);
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;
this.setStyles(el);
},
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.style.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";
this.setStyles(el);
},
leave(el) {
let leaveDuration = this.duration.leave
? this.duration.leave
: this.duration;
if (el.scrollHeight !== 0) {
// for safari: add class after set height, or it will jump to zero height suddenly, weired
el.style.transition = this.transitionStyle(leaveDuration);
el.style.height = 0;
el.style.paddingTop = 0;
el.style.paddingBottom = 0;
}
// necessary for transition-group
this.setAbsolutePosition(el);
},
afterLeave(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;
}
},
render(h) {
return h(
"transition",
{
props: {
is: this.componentType,
tag: this.tag
},
on: {
"before-enter": this.beforeEnter,
"after-enter": this.afterEnter,
enter: this.enter,
"before-leave": this.beforeLeave,
leave: this.leave,
"after-leave": this.afterLeave
}
},
this.$slots.default
);
}
});
collapseMixins.js是一个混合类,因为我封装了其他不同类型的动画,所以做了一个mixins。
使用的时候引入collapseTransition组件就行。
<collapse-transition>
<div v-show="show">
...
</div>
</collapse-transition>