158 lines
		
	
	
		
			6.1 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
		
		
			
		
	
	
			158 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('enter') | |||
|  |                 this.transitionEnded = false | |||
|  | 				// 组件动画进入后触发的事件
 | |||
|  |                 this.$emit('afterEnter') | |||
|  |                 // 赋予组件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 | |||
|  |                this.$emit('leave') | |||
|  |                 // 组件执行动画,到了执行的执行时间后,执行一些额外处理
 | |||
|  |                 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 | |||
|  |             } | |||
|  |         } | |||
|  |     } | |||
|  | } |