You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
174 lines
4.8 KiB
174 lines
4.8 KiB
<template>
|
|
<view
|
|
:id="$sUid"
|
|
class="s-transition"
|
|
:class="c_class"
|
|
:style="c_style"
|
|
@animationend="onAnimationend"
|
|
>
|
|
<slot />
|
|
</view>
|
|
</template>
|
|
|
|
<script>
|
|
import componentMixin from '../../mixins/componentMixin';
|
|
|
|
/**
|
|
* s-transition 动画
|
|
* @description 用来控制一个元素显示隐藏时的动画
|
|
* @property {Boolean} value v-model双向绑定显示隐藏
|
|
* @property {String|Object|Boolean} name = [false|fade-top|slide-top|{enter:'fade',leave:'fade-top'}] 过渡效果 ,为s-ui styles下animate.scss中定义的效果
|
|
* @property {Number|String|Object} duration 动画执行时间
|
|
* @property {String} enterClass 进入过渡时自定义class
|
|
* @property {String} leaveClass 离开过渡时自定义class
|
|
* @event {Function} before-enter 进入过渡的开始前触发
|
|
* @event {Function} enter 进入过渡时触发
|
|
* @event {Function} before-leave 离开过渡的开始前触发
|
|
* @event {Function} leave 离开过渡时触发
|
|
* @example <s-transition v-model="visible"></s-transition>
|
|
*/
|
|
export default {
|
|
name: 'STransition',
|
|
mixins: [componentMixin],
|
|
props: {
|
|
value: Boolean,
|
|
name: {
|
|
type: [String, Object, Boolean],
|
|
default: 'fade',
|
|
},
|
|
duration: {
|
|
type: [Number, String, Object],
|
|
default: 300,
|
|
},
|
|
namePrefix: {
|
|
type: String,
|
|
default: 's-animate',
|
|
},
|
|
enterClass: String,
|
|
leaveClass: String,
|
|
},
|
|
data: () => ({
|
|
animateStatus: '',
|
|
isVisible: false,
|
|
}),
|
|
computed: {
|
|
c_class() {
|
|
const { animateStatus, namePrefix, custom_class } = this;
|
|
const animateName = this.animateStatus ? this.animateMap[this.animateStatus].name : '';
|
|
const animateClass = animateName ? `${namePrefix ? namePrefix + '-' : ''}${animateName}-${this.animateStatus}` : '';
|
|
return this.$mergeClass(
|
|
{
|
|
's-transition--enter': animateStatus === 'enter',
|
|
's-transition--leave': animateStatus === 'leave',
|
|
},
|
|
animateClass,
|
|
animateStatus === 'enter' ? this.enterClass : '',
|
|
animateStatus === 'leave' ? this.leaveClass : '',
|
|
custom_class,
|
|
);
|
|
},
|
|
c_style() {
|
|
return this.$mergeStyle({
|
|
animationDuration: this.animateStatus ? this.animateMap[this.animateStatus].duration + 'ms' : '',
|
|
display: this.isVisible ? '' : 'none',
|
|
}, this.custom_style);
|
|
},
|
|
animateMap() {
|
|
let animate = this.name;
|
|
let duration = this.duration;
|
|
|
|
if (this.$getType(animate) !== 'object') {
|
|
animate = { enter: animate, leave: animate };
|
|
}
|
|
|
|
if (this.$getType(duration) !== 'object') {
|
|
duration = { enter: duration, leave: duration };
|
|
}
|
|
|
|
return {
|
|
enter: {
|
|
name: animate.enter,
|
|
duration: parseInt(animate.enter ? duration.enter : 0) || 0,
|
|
},
|
|
leave: {
|
|
name: animate.leave,
|
|
duration: parseInt(animate.leave ? duration.leave : 0) || 0,
|
|
},
|
|
};
|
|
},
|
|
},
|
|
watch: {
|
|
value() {
|
|
this.updateVisible();
|
|
},
|
|
},
|
|
created() {
|
|
Object.assign(this, {
|
|
visibleStatus: false,
|
|
animationendCallback: null,
|
|
});
|
|
},
|
|
mounted() {
|
|
this.updateVisible();
|
|
},
|
|
beforeDestroy() {
|
|
this.removeAnimationendCallback();
|
|
},
|
|
methods: {
|
|
updateVisible() {
|
|
if (this._isMounted && this.visibleStatus !== this.value) {
|
|
this[this.value ? 'show' : 'hide']();
|
|
}
|
|
},
|
|
setAnimationendCallback(callback, duration) {
|
|
if (duration > 0) {
|
|
this.animationendCallback = callback;
|
|
} else {
|
|
callback();
|
|
}
|
|
},
|
|
removeAnimationendCallback() {
|
|
if (this.animationendCallback) {
|
|
this.animationendCallback = null;
|
|
}
|
|
},
|
|
onAnimationend(e) {
|
|
if (e.target.id === this.$sUid && this.animationendCallback) {
|
|
this.animationendCallback();
|
|
this.animationendCallback = null;
|
|
}
|
|
},
|
|
show() {
|
|
if (!this.visibleStatus) {
|
|
this.removeAnimationendCallback();
|
|
this.visibleStatus = true;
|
|
this.animateStatus = 'enter';
|
|
this.isVisible = true;
|
|
this.$emit('input', true);
|
|
this.$emit('before-enter');
|
|
this.setAnimationendCallback(() => {
|
|
this.animateStatus = '';
|
|
this.$emit('enter');
|
|
}, this.animateMap.enter.duration);
|
|
}
|
|
},
|
|
hide() {
|
|
if (this.visibleStatus) {
|
|
this.removeAnimationendCallback();
|
|
this.visibleStatus = false;
|
|
this.animateStatus = 'leave';
|
|
this.$emit('input', false);
|
|
this.$emit('before-leave');
|
|
this.setAnimationendCallback(() => {
|
|
this.isVisible = false;
|
|
this.zIndexValue = 0;
|
|
this.animateStatus = '';
|
|
this.$emit('leave');
|
|
}, this.animateMap.leave.duration);
|
|
}
|
|
},
|
|
},
|
|
};
|
|
</script>
|
|
|
|
<style lang="scss" src="./index.scss"></style>
|
|
|