|
|
|
|
@@ -1,23 +1,14 @@
|
|
|
|
|
<template>
|
|
|
|
|
<view
|
|
|
|
|
v-if="isShow"
|
|
|
|
|
ref="ani"
|
|
|
|
|
:animation="animationData"
|
|
|
|
|
:class="customClass"
|
|
|
|
|
:style="transformStyles"
|
|
|
|
|
@click="onClick"
|
|
|
|
|
>
|
|
|
|
|
<slot></slot>
|
|
|
|
|
</view>
|
|
|
|
|
<!-- #ifdef MP -->
|
|
|
|
|
<view v-else style="display: none">
|
|
|
|
|
<slot></slot>
|
|
|
|
|
</view>
|
|
|
|
|
<!-- #ifndef APP-NVUE -->
|
|
|
|
|
<view v-show="isShow" ref="ani" :animation="animationData" :class="customClass" :style="transformStyles" @click="onClick"><slot></slot></view>
|
|
|
|
|
<!-- #endif -->
|
|
|
|
|
<!-- #ifdef APP-NVUE -->
|
|
|
|
|
<view v-if="isShow" ref="ani" :animation="animationData" :class="customClass" :style="transformStyles" @click="onClick"><slot></slot></view>
|
|
|
|
|
<!-- #endif -->
|
|
|
|
|
</template>
|
|
|
|
|
|
|
|
|
|
<script>
|
|
|
|
|
import { createAnimation } from './createAnimation';
|
|
|
|
|
import { createAnimation } from './createAnimation'
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Transition 过渡动画
|
|
|
|
|
@@ -37,7 +28,7 @@ import { createAnimation } from './createAnimation';
|
|
|
|
|
*/
|
|
|
|
|
export default {
|
|
|
|
|
name: 'uniTransition',
|
|
|
|
|
emits: ['click', 'change'],
|
|
|
|
|
emits:['click','change'],
|
|
|
|
|
props: {
|
|
|
|
|
show: {
|
|
|
|
|
type: Boolean,
|
|
|
|
|
@@ -46,7 +37,7 @@ export default {
|
|
|
|
|
modeClass: {
|
|
|
|
|
type: [Array, String],
|
|
|
|
|
default() {
|
|
|
|
|
return 'fade';
|
|
|
|
|
return 'fade'
|
|
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
duration: {
|
|
|
|
|
@@ -56,13 +47,17 @@ export default {
|
|
|
|
|
styles: {
|
|
|
|
|
type: Object,
|
|
|
|
|
default() {
|
|
|
|
|
return {};
|
|
|
|
|
return {}
|
|
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
customClass: {
|
|
|
|
|
customClass:{
|
|
|
|
|
type: String,
|
|
|
|
|
default: ''
|
|
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
onceRender:{
|
|
|
|
|
type:Boolean,
|
|
|
|
|
default:false
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
data() {
|
|
|
|
|
return {
|
|
|
|
|
@@ -72,17 +67,17 @@ export default {
|
|
|
|
|
animationData: {},
|
|
|
|
|
durationTime: 300,
|
|
|
|
|
config: {}
|
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
watch: {
|
|
|
|
|
show: {
|
|
|
|
|
handler(newVal) {
|
|
|
|
|
if (newVal) {
|
|
|
|
|
this.open();
|
|
|
|
|
this.open()
|
|
|
|
|
} else {
|
|
|
|
|
// 避免上来就执行 close,导致动画错乱
|
|
|
|
|
if (this.isShow) {
|
|
|
|
|
this.close();
|
|
|
|
|
this.close()
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
@@ -95,25 +90,17 @@ export default {
|
|
|
|
|
let styles = {
|
|
|
|
|
...this.styles,
|
|
|
|
|
'transition-duration': this.duration / 1000 + 's'
|
|
|
|
|
};
|
|
|
|
|
let transform = '';
|
|
|
|
|
for (let i in styles) {
|
|
|
|
|
let line = this.toLine(i);
|
|
|
|
|
transform += line + ':' + styles[i] + ';';
|
|
|
|
|
}
|
|
|
|
|
return transform;
|
|
|
|
|
let transform = ''
|
|
|
|
|
for (let i in styles) {
|
|
|
|
|
let line = this.toLine(i)
|
|
|
|
|
transform += line + ':' + styles[i] + ';'
|
|
|
|
|
}
|
|
|
|
|
return transform
|
|
|
|
|
},
|
|
|
|
|
// 初始化动画条件
|
|
|
|
|
transformStyles() {
|
|
|
|
|
return (
|
|
|
|
|
'transform:' +
|
|
|
|
|
this.transform +
|
|
|
|
|
';' +
|
|
|
|
|
'opacity:' +
|
|
|
|
|
this.opacity +
|
|
|
|
|
';' +
|
|
|
|
|
this.stylesObject
|
|
|
|
|
);
|
|
|
|
|
return 'transform:' + this.transform + ';' + 'opacity:' + this.opacity + ';' + this.stylesObject
|
|
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
created() {
|
|
|
|
|
@@ -123,8 +110,8 @@ export default {
|
|
|
|
|
timingFunction: 'ease',
|
|
|
|
|
transformOrigin: '50% 50%',
|
|
|
|
|
delay: 0
|
|
|
|
|
};
|
|
|
|
|
this.durationTime = this.duration;
|
|
|
|
|
}
|
|
|
|
|
this.durationTime = this.duration
|
|
|
|
|
},
|
|
|
|
|
methods: {
|
|
|
|
|
/**
|
|
|
|
|
@@ -132,9 +119,9 @@ export default {
|
|
|
|
|
*/
|
|
|
|
|
init(obj = {}) {
|
|
|
|
|
if (obj.duration) {
|
|
|
|
|
this.durationTime = obj.duration;
|
|
|
|
|
this.durationTime = obj.duration
|
|
|
|
|
}
|
|
|
|
|
this.animation = createAnimation(Object.assign(this.config, obj), this);
|
|
|
|
|
this.animation = createAnimation(Object.assign(this.config, obj),this)
|
|
|
|
|
},
|
|
|
|
|
/**
|
|
|
|
|
* 点击组件触发回调
|
|
|
|
|
@@ -142,139 +129,139 @@ export default {
|
|
|
|
|
onClick() {
|
|
|
|
|
this.$emit('click', {
|
|
|
|
|
detail: this.isShow
|
|
|
|
|
});
|
|
|
|
|
})
|
|
|
|
|
},
|
|
|
|
|
/**
|
|
|
|
|
* ref 触发 动画分组
|
|
|
|
|
* @param {Object} obj
|
|
|
|
|
*/
|
|
|
|
|
step(obj, config = {}) {
|
|
|
|
|
if (!this.animation) return;
|
|
|
|
|
if (!this.animation) return
|
|
|
|
|
for (let i in obj) {
|
|
|
|
|
try {
|
|
|
|
|
if (typeof obj[i] === 'object') {
|
|
|
|
|
this.animation[i](...obj[i]);
|
|
|
|
|
} else {
|
|
|
|
|
this.animation[i](obj[i]);
|
|
|
|
|
if(typeof obj[i] === 'object'){
|
|
|
|
|
this.animation[i](...obj[i])
|
|
|
|
|
}else{
|
|
|
|
|
this.animation[i](obj[i])
|
|
|
|
|
}
|
|
|
|
|
} catch (e) {
|
|
|
|
|
console.error(`方法 ${i} 不存在`);
|
|
|
|
|
console.error(`方法 ${i} 不存在`)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
this.animation.step(config);
|
|
|
|
|
return this;
|
|
|
|
|
this.animation.step(config)
|
|
|
|
|
return this
|
|
|
|
|
},
|
|
|
|
|
/**
|
|
|
|
|
* ref 触发 执行动画
|
|
|
|
|
*/
|
|
|
|
|
run(fn) {
|
|
|
|
|
if (!this.animation) return;
|
|
|
|
|
this.animation.run(fn);
|
|
|
|
|
if (!this.animation) return
|
|
|
|
|
this.animation.run(fn)
|
|
|
|
|
},
|
|
|
|
|
// 开始过度动画
|
|
|
|
|
open() {
|
|
|
|
|
clearTimeout(this.timer);
|
|
|
|
|
this.transform = '';
|
|
|
|
|
this.isShow = true;
|
|
|
|
|
let { opacity, transform } = this.styleInit(false);
|
|
|
|
|
clearTimeout(this.timer)
|
|
|
|
|
this.transform = ''
|
|
|
|
|
this.isShow = true
|
|
|
|
|
let { opacity, transform } = this.styleInit(false)
|
|
|
|
|
if (typeof opacity !== 'undefined') {
|
|
|
|
|
this.opacity = opacity;
|
|
|
|
|
this.opacity = opacity
|
|
|
|
|
}
|
|
|
|
|
this.transform = transform;
|
|
|
|
|
this.transform = transform
|
|
|
|
|
// 确保动态样式已经生效后,执行动画,如果不加 nextTick ,会导致 wx 动画执行异常
|
|
|
|
|
this.$nextTick(() => {
|
|
|
|
|
// TODO 定时器保证动画完全执行,目前有些问题,后面会取消定时器
|
|
|
|
|
this.timer = setTimeout(() => {
|
|
|
|
|
this.animation = createAnimation(this.config, this);
|
|
|
|
|
this.tranfromInit(false).step();
|
|
|
|
|
this.animation.run();
|
|
|
|
|
this.animation = createAnimation(this.config, this)
|
|
|
|
|
this.tranfromInit(false).step()
|
|
|
|
|
this.animation.run()
|
|
|
|
|
this.$emit('change', {
|
|
|
|
|
detail: this.isShow
|
|
|
|
|
});
|
|
|
|
|
}, 20);
|
|
|
|
|
});
|
|
|
|
|
})
|
|
|
|
|
}, 20)
|
|
|
|
|
})
|
|
|
|
|
},
|
|
|
|
|
// 关闭过度动画
|
|
|
|
|
close(type) {
|
|
|
|
|
if (!this.animation) return;
|
|
|
|
|
if (!this.animation) return
|
|
|
|
|
this.tranfromInit(true)
|
|
|
|
|
.step()
|
|
|
|
|
.run(() => {
|
|
|
|
|
this.isShow = false;
|
|
|
|
|
this.animationData = null;
|
|
|
|
|
this.animation = null;
|
|
|
|
|
let { opacity, transform } = this.styleInit(false);
|
|
|
|
|
this.opacity = opacity || 1;
|
|
|
|
|
this.transform = transform;
|
|
|
|
|
this.isShow = false
|
|
|
|
|
this.animationData = null
|
|
|
|
|
this.animation = null
|
|
|
|
|
let { opacity, transform } = this.styleInit(false)
|
|
|
|
|
this.opacity = opacity || 1
|
|
|
|
|
this.transform = transform
|
|
|
|
|
this.$emit('change', {
|
|
|
|
|
detail: this.isShow
|
|
|
|
|
});
|
|
|
|
|
});
|
|
|
|
|
})
|
|
|
|
|
})
|
|
|
|
|
},
|
|
|
|
|
// 处理动画开始前的默认样式
|
|
|
|
|
styleInit(type) {
|
|
|
|
|
let styles = {
|
|
|
|
|
transform: ''
|
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
let buildStyle = (type, mode) => {
|
|
|
|
|
if (mode === 'fade') {
|
|
|
|
|
styles.opacity = this.animationType(type)[mode];
|
|
|
|
|
styles.opacity = this.animationType(type)[mode]
|
|
|
|
|
} else {
|
|
|
|
|
styles.transform += this.animationType(type)[mode] + ' ';
|
|
|
|
|
styles.transform += this.animationType(type)[mode] + ' '
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
if (typeof this.modeClass === 'string') {
|
|
|
|
|
buildStyle(type, this.modeClass);
|
|
|
|
|
buildStyle(type, this.modeClass)
|
|
|
|
|
} else {
|
|
|
|
|
this.modeClass.forEach(mode => {
|
|
|
|
|
buildStyle(type, mode);
|
|
|
|
|
});
|
|
|
|
|
buildStyle(type, mode)
|
|
|
|
|
})
|
|
|
|
|
}
|
|
|
|
|
return styles;
|
|
|
|
|
return styles
|
|
|
|
|
},
|
|
|
|
|
// 处理内置组合动画
|
|
|
|
|
tranfromInit(type) {
|
|
|
|
|
let buildTranfrom = (type, mode) => {
|
|
|
|
|
let aniNum = null;
|
|
|
|
|
let aniNum = null
|
|
|
|
|
if (mode === 'fade') {
|
|
|
|
|
aniNum = type ? 0 : 1;
|
|
|
|
|
aniNum = type ? 0 : 1
|
|
|
|
|
} else {
|
|
|
|
|
aniNum = type ? '-100%' : '0';
|
|
|
|
|
aniNum = type ? '-100%' : '0'
|
|
|
|
|
if (mode === 'zoom-in') {
|
|
|
|
|
aniNum = type ? 0.8 : 1;
|
|
|
|
|
aniNum = type ? 0.8 : 1
|
|
|
|
|
}
|
|
|
|
|
if (mode === 'zoom-out') {
|
|
|
|
|
aniNum = type ? 1.2 : 1;
|
|
|
|
|
aniNum = type ? 1.2 : 1
|
|
|
|
|
}
|
|
|
|
|
if (mode === 'slide-right') {
|
|
|
|
|
aniNum = type ? '100%' : '0';
|
|
|
|
|
aniNum = type ? '100%' : '0'
|
|
|
|
|
}
|
|
|
|
|
if (mode === 'slide-bottom') {
|
|
|
|
|
aniNum = type ? '100%' : '0';
|
|
|
|
|
aniNum = type ? '100%' : '0'
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
this.animation[this.animationMode()[mode]](aniNum);
|
|
|
|
|
};
|
|
|
|
|
this.animation[this.animationMode()[mode]](aniNum)
|
|
|
|
|
}
|
|
|
|
|
if (typeof this.modeClass === 'string') {
|
|
|
|
|
buildTranfrom(type, this.modeClass);
|
|
|
|
|
buildTranfrom(type, this.modeClass)
|
|
|
|
|
} else {
|
|
|
|
|
this.modeClass.forEach(mode => {
|
|
|
|
|
buildTranfrom(type, mode);
|
|
|
|
|
});
|
|
|
|
|
buildTranfrom(type, mode)
|
|
|
|
|
})
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return this.animation;
|
|
|
|
|
return this.animation
|
|
|
|
|
},
|
|
|
|
|
animationType(type) {
|
|
|
|
|
return {
|
|
|
|
|
fade: type ? 1 : 0,
|
|
|
|
|
fade: type ? 0 : 1,
|
|
|
|
|
'slide-top': `translateY(${type ? '0' : '-100%'})`,
|
|
|
|
|
'slide-right': `translateX(${type ? '0' : '100%'})`,
|
|
|
|
|
'slide-bottom': `translateY(${type ? '0' : '100%'})`,
|
|
|
|
|
'slide-left': `translateX(${type ? '0' : '-100%'})`,
|
|
|
|
|
'zoom-in': `scaleX(${type ? 1 : 0.8}) scaleY(${type ? 1 : 0.8})`,
|
|
|
|
|
'zoom-out': `scaleX(${type ? 1 : 1.2}) scaleY(${type ? 1 : 1.2})`
|
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
// 内置动画类型与实际动画对应字典
|
|
|
|
|
animationMode() {
|
|
|
|
|
@@ -286,14 +273,14 @@ export default {
|
|
|
|
|
'slide-left': 'translateX',
|
|
|
|
|
'zoom-in': 'scale',
|
|
|
|
|
'zoom-out': 'scale'
|
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
// 驼峰转中横线
|
|
|
|
|
toLine(name) {
|
|
|
|
|
return name.replace(/([A-Z])/g, '-$1').toLowerCase();
|
|
|
|
|
return name.replace(/([A-Z])/g, '-$1').toLowerCase()
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
</script>
|
|
|
|
|
|
|
|
|
|
<style></style>
|
|
|
|
|
|