transition.js
6.2 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
// 定义一个一定时间后自动成功的promise,让调用nextTick方法处,进入下一个then方法
const nextTick = () => new Promise(resolve => setTimeout(resolve, 1000 / 50))
// nvue动画模块实现细节抽离在外部文件
// #ifdef APP-NVUE
import animationMap from './nvue-ani-map.js'
// #endif
// #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
}
}
}
}