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.
279 lines
5.7 KiB
279 lines
5.7 KiB
<template> |
|
<view v-if="isShow" ref="ani" class="uni-transition" :class="[ani.in]" :style="'transform:' +transform+';'+stylesObject" |
|
@click="change"> |
|
<slot></slot> |
|
</view> |
|
</template> |
|
|
|
<script> |
|
// #ifdef APP-NVUE |
|
const animation = uni.requireNativePlugin('animation'); |
|
// #endif |
|
/** |
|
* Transition 过渡动画 |
|
* @description 简单过渡动画组件 |
|
* @tutorial https://ext.dcloud.net.cn/plugin?id=985 |
|
* @property {Boolean} show = [false|true] 控制组件显示或隐藏 |
|
* @property {Array} modeClass = [fade|slide-top|slide-right|slide-bottom|slide-left|zoom-in|zoom-out] 过渡动画类型 |
|
* @value fade 渐隐渐出过渡 |
|
* @value slide-top 由上至下过渡 |
|
* @value slide-right 由右至左过渡 |
|
* @value slide-bottom 由下至上过渡 |
|
* @value slide-left 由左至右过渡 |
|
* @value zoom-in 由小到大过渡 |
|
* @value zoom-out 由大到小过渡 |
|
* @property {Number} duration 过渡动画持续时间 |
|
* @property {Object} styles 组件样式,同 css 样式,注意带’-‘连接符的属性需要使用小驼峰写法如:`backgroundColor:red` |
|
*/ |
|
export default { |
|
name: 'uniTransition', |
|
props: { |
|
show: { |
|
type: Boolean, |
|
default: false |
|
}, |
|
modeClass: { |
|
type: Array, |
|
default () { |
|
return [] |
|
} |
|
}, |
|
duration: { |
|
type: Number, |
|
default: 300 |
|
}, |
|
styles: { |
|
type: Object, |
|
default () { |
|
return {} |
|
} |
|
} |
|
}, |
|
data() { |
|
return { |
|
isShow: false, |
|
transform: '', |
|
ani: { in: '', |
|
active: '' |
|
} |
|
}; |
|
}, |
|
watch: { |
|
show: { |
|
handler(newVal) { |
|
if (newVal) { |
|
this.open() |
|
} else { |
|
this.close() |
|
} |
|
}, |
|
immediate: true |
|
} |
|
}, |
|
computed: { |
|
stylesObject() { |
|
let styles = { |
|
...this.styles, |
|
'transition-duration': this.duration / 1000 + 's' |
|
} |
|
let transfrom = '' |
|
for (let i in styles) { |
|
let line = this.toLine(i) |
|
transfrom += line + ':' + styles[i] + ';' |
|
} |
|
return transfrom |
|
} |
|
}, |
|
created() { |
|
// this.timer = null |
|
// this.nextTick = (time = 50) => new Promise(resolve => { |
|
// clearTimeout(this.timer) |
|
// this.timer = setTimeout(resolve, time) |
|
// return this.timer |
|
// }); |
|
}, |
|
methods: { |
|
change() { |
|
this.$emit('click', { |
|
detail: this.isShow |
|
}) |
|
}, |
|
open() { |
|
clearTimeout(this.timer) |
|
this.isShow = true |
|
this.transform = '' |
|
this.ani.in = '' |
|
for (let i in this.getTranfrom(false)) { |
|
if (i === 'opacity') { |
|
this.ani.in = 'fade-in' |
|
} else { |
|
this.transform += `${this.getTranfrom(false)[i]} ` |
|
} |
|
} |
|
this.$nextTick(() => { |
|
setTimeout(() => { |
|
this._animation(true) |
|
}, 50) |
|
}) |
|
|
|
}, |
|
close(type) { |
|
clearTimeout(this.timer) |
|
this._animation(false) |
|
}, |
|
_animation(type) { |
|
let styles = this.getTranfrom(type) |
|
// #ifdef APP-NVUE |
|
if(!this.$refs['ani']) return |
|
animation.transition(this.$refs['ani'].ref, { |
|
styles, |
|
duration: this.duration, //ms |
|
timingFunction: 'ease', |
|
needLayout: false, |
|
delay: 0 //ms |
|
}, () => { |
|
if (!type) { |
|
this.isShow = false |
|
} |
|
this.$emit('change', { |
|
detail: this.isShow |
|
}) |
|
}) |
|
// #endif |
|
// #ifndef APP-NVUE |
|
this.transform = '' |
|
for (let i in styles) { |
|
if (i === 'opacity') { |
|
this.ani.in = `fade-${type?'out':'in'}` |
|
} else { |
|
this.transform += `${styles[i]} ` |
|
} |
|
} |
|
this.timer = setTimeout(() => { |
|
if (!type) { |
|
this.isShow = false |
|
} |
|
this.$emit('change', { |
|
detail: this.isShow |
|
}) |
|
|
|
}, this.duration) |
|
// #endif |
|
|
|
}, |
|
getTranfrom(type) { |
|
let styles = { |
|
transform: '' |
|
} |
|
this.modeClass.forEach((mode) => { |
|
switch (mode) { |
|
case 'fade': |
|
styles.opacity = type ? 1 : 0 |
|
break; |
|
case 'slide-top': |
|
styles.transform += `translateY(${type?'0':'-100%'}) ` |
|
break; |
|
case 'slide-right': |
|
styles.transform += `translateX(${type?'0':'100%'}) ` |
|
break; |
|
case 'slide-bottom': |
|
styles.transform += `translateY(${type?'0':'100%'}) ` |
|
break; |
|
case 'slide-left': |
|
styles.transform += `translateX(${type?'0':'-100%'}) ` |
|
break; |
|
case 'zoom-in': |
|
styles.transform += `scale(${type?1:0.8}) ` |
|
break; |
|
case 'zoom-out': |
|
styles.transform += `scale(${type?1:1.2}) ` |
|
break; |
|
} |
|
}) |
|
return styles |
|
}, |
|
_modeClassArr(type) { |
|
let mode = this.modeClass |
|
if (typeof(mode) !== "string") { |
|
let modestr = '' |
|
mode.forEach((item) => { |
|
modestr += (item + '-' + type + ',') |
|
}) |
|
return modestr.substr(0, modestr.length - 1) |
|
} else { |
|
return mode + '-' + type |
|
} |
|
}, |
|
// getEl(el) { |
|
// console.log(el || el.ref || null); |
|
// return el || el.ref || null |
|
// }, |
|
toLine(name) { |
|
return name.replace(/([A-Z])/g, "-$1").toLowerCase(); |
|
} |
|
} |
|
} |
|
</script> |
|
|
|
<style> |
|
.uni-transition { |
|
transition-timing-function: ease; |
|
transition-duration: 0.3s; |
|
transition-property: transform, opacity; |
|
} |
|
|
|
.fade-in { |
|
opacity: 0; |
|
} |
|
|
|
.fade-active { |
|
opacity: 1; |
|
} |
|
|
|
.slide-top-in { |
|
/* transition-property: transform, opacity; */ |
|
transform: translateY(-100%); |
|
} |
|
|
|
.slide-top-active { |
|
transform: translateY(0); |
|
/* opacity: 1; */ |
|
} |
|
|
|
.slide-right-in { |
|
transform: translateX(100%); |
|
} |
|
|
|
.slide-right-active { |
|
transform: translateX(0); |
|
} |
|
|
|
.slide-bottom-in { |
|
transform: translateY(100%); |
|
} |
|
|
|
.slide-bottom-active { |
|
transform: translateY(0); |
|
} |
|
|
|
.slide-left-in { |
|
transform: translateX(-100%); |
|
} |
|
|
|
.slide-left-active { |
|
transform: translateX(0); |
|
opacity: 1; |
|
} |
|
|
|
.zoom-in-in { |
|
transform: scale(0.8); |
|
} |
|
|
|
.zoom-out-active { |
|
transform: scale(1); |
|
} |
|
|
|
.zoom-out-in { |
|
transform: scale(1.2); |
|
} |
|
</style>
|
|
|