156 lines
6.1 KiB
JavaScript
156 lines
6.1 KiB
JavaScript
// 定义一个一定时间后自动成功的promise,让调用nextTick方法处,进入下一个then方法
|
||
const nextTick = () => new Promise(resolve => setTimeout(resolve, 1000 / 50))
|
||
// nvue动画模块实现细节抽离在外部文件
|
||
import animationMap from './nvue.ani-map.js'
|
||
|
||
// #ifndef APP-NVUE
|
||
// 定义类名,通过给元素动态切换类名,赋予元素一定的css动画样式
|
||
const getClassNames = (name) => ({
|
||
enter: `u-${name}-enter u-${name}-enter-active`,
|
||
'enter-to': `u-${name}-enter-to u-${name}-enter-active`,
|
||
leave: `u-${name}-leave u-${name}-leave-active`,
|
||
'leave-to': `u-${name}-leave-to u-${name}-leave-active`
|
||
})
|
||
// #endif
|
||
|
||
// #ifdef APP-NVUE
|
||
// 引入nvue(weex)的animation动画模块,文档见:
|
||
// https://weex.apache.org/zh/docs/modules/animation.html#transition
|
||
const animation = uni.requireNativePlugin('animation')
|
||
const getStyle = (name) => animationMap[name]
|
||
// #endif
|
||
|
||
export default {
|
||
methods: {
|
||
// 组件被点击发出事件
|
||
clickHandler() {
|
||
this.$emit('click')
|
||
},
|
||
// #ifndef APP-NVUE
|
||
// vue版本的组件进场处理
|
||
vueEnter() {
|
||
// 动画进入时的类名
|
||
const classNames = getClassNames(this.mode)
|
||
// 定义状态和发出动画进入前事件
|
||
this.status = 'enter'
|
||
this.$emit('beforeEnter')
|
||
this.inited = true
|
||
this.display = true
|
||
this.classes = classNames.enter
|
||
this.$nextTick(async () => {
|
||
// #ifdef H5
|
||
await uni.$u.sleep(20)
|
||
// #endif
|
||
// 组件动画进入后触发的事件
|
||
this.$emit('afterEnter')
|
||
// 标识动画尚未结束
|
||
this.transitionEnded = false
|
||
// 赋予组件enter-to类名
|
||
this.classes = classNames['enter-to']
|
||
})
|
||
},
|
||
// 动画离场处理
|
||
vueLeave() {
|
||
// 如果不是展示状态,无需执行逻辑
|
||
if (!this.display) return
|
||
const classNames = getClassNames(this.mode)
|
||
// 标记离开状态和发出事件
|
||
this.status = 'leave'
|
||
this.$emit('beforeLeave')
|
||
// 获得类名
|
||
this.classes = classNames.leave
|
||
|
||
this.$nextTick(() => {
|
||
// 标记动画已经结束了
|
||
this.transitionEnded = false
|
||
// 组件执行动画,到了执行的执行时间后,执行一些额外处理
|
||
setTimeout(this.onTransitionEnd, this.duration)
|
||
this.classes = classNames['leave-to']
|
||
})
|
||
},
|
||
// #endif
|
||
// #ifdef APP-NVUE
|
||
// nvue版本动画进场
|
||
nvueEnter() {
|
||
// 获得样式的名称
|
||
const currentStyle = getStyle(this.mode)
|
||
// 组件动画状态和发出事件
|
||
this.status = 'enter'
|
||
this.$emit('beforeEnter')
|
||
// 展示生成组件元素
|
||
this.inited = true
|
||
this.display = true
|
||
// 在nvue安卓上,由于渲染速度慢,在弹窗,键盘,日历等组件中,渲染其中的内容需要时间
|
||
// 导致出现弹窗卡顿,这里让其一开始为透明状态,等一定时间渲染完成后,再让其隐藏起来,再让其按正常逻辑出现
|
||
this.viewStyle = {
|
||
opacity: 0
|
||
}
|
||
// 等待弹窗内容渲染完成
|
||
this.$nextTick(() => {
|
||
// 合并样式
|
||
this.viewStyle = currentStyle.enter
|
||
Promise.resolve()
|
||
.then(nextTick)
|
||
.then(() => {
|
||
// 组件开始进入前的事件
|
||
this.$emit('enter')
|
||
// nvue的transition动画模块需要通过ref调用组件,注意此处的ref不同于vue的this.$refs['u-transition']用法
|
||
animation.transition(this.$refs['u-transition'].ref, {
|
||
styles: currentStyle['enter-to'],
|
||
duration: this.duration,
|
||
timingFunction: this.timingFunction,
|
||
needLayout: false,
|
||
delay: 0
|
||
}, () => {
|
||
// 动画执行完毕,发出事件
|
||
this.$emit('afterEnter')
|
||
})
|
||
})
|
||
.catch(() => {})
|
||
})
|
||
},
|
||
nvueLeave() {
|
||
if (!this.display) {
|
||
return
|
||
}
|
||
const currentStyle = getStyle(this.mode)
|
||
// 定义状态和事件
|
||
this.status = 'leave'
|
||
this.$emit('beforeLeave')
|
||
// 合并样式
|
||
this.viewStyle = currentStyle.leave
|
||
// 放到promise中处理执行过程
|
||
Promise.resolve()
|
||
.then(nextTick) // 等待几十ms
|
||
.then(() => {
|
||
this.transitionEnded = false
|
||
// 动画正在离场的状态
|
||
this.$emit('leave')
|
||
animation.transition(this.$refs['u-transition'].ref, {
|
||
styles: currentStyle['leave-to'],
|
||
duration: this.duration,
|
||
timingFunction: this.timingFunction,
|
||
needLayout: false,
|
||
delay: 0
|
||
}, () => {
|
||
this.onTransitionEnd()
|
||
})
|
||
})
|
||
.catch(() => {})
|
||
},
|
||
// #endif
|
||
// 完成过渡后触发
|
||
onTransitionEnd() {
|
||
// 如果已经是结束的状态,无需再处理
|
||
if (this.transitionEnded) return
|
||
this.transitionEnded = true
|
||
// 发出组件动画执行后的事件
|
||
this.$emit(this.status === 'leave' ? 'afterLeave' : 'afterEnter')
|
||
if (!this.show && this.display) {
|
||
this.display = false
|
||
this.inited = false
|
||
}
|
||
}
|
||
}
|
||
}
|