之前封裝手風(fēng)琴的時候借鑒列element做了個collapse折疊板動畫糊余。
網(wǎng)上有個大神也做了個collapse折疊板動畫秀又。傳送門這里贊最多的就是element的那個動畫。
我的那個element動畫也是這個贬芥,vue 自定義指令封裝一個手風(fēng)琴嵌套組件這里的組件過度動畫
但是這個動畫并不支持設(shè)置時間吐辙,進(jìn)一步封裝還是可以的。
重寫了一個collapse 的動畫蘸劈。
效果如下
新建collapseMixins.js昏苏,內(nèi)容如下
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,內(nèi)容如下
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>