8000 feat: add transition component · VRDate/nativescript-vue@4951821 · GitHub
[go: up one dir, main page]

Skip to content

Commit 4951821

Browse files
committed
feat: add transition component
implements nativescript-vue#110
1 parent 9a9d103 commit 4951821

File tree

8 files changed

+376
-9
lines changed

8 files changed

+376
-9
lines changed

platform/nativescript/renderer/ViewNode.js

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,10 @@ export default class ViewNode {
8787
return (this._ownerDocument = el)
8888
}
8989

90+
getAttribute(key) {
91+
return this.nativeView[key]
92+
}
93+
9094
/* istanbul ignore next */
9195
setAttribute(key, value) {
9296
try {
Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,23 @@
11
import ActionBar from './action-bar'
22
import ActionItem from './action-item'
3+
import android from './android'
4+
import ios from './ios'
35
import ListView from './list-view'
46
import NavigationButton from './navigation-button'
57
import TabView from './tab-view'
68
import TabViewItem from './tab-view-item'
9+
import transition from './transition'
710
import VTemplate from './v-template'
8-
import android from './android'
9-
import ios from './ios'
1011

1112
export default {
1213
ActionBar,
1314
ActionItem,
15+
android,
16+
ios,
1417
ListView,
1518
NavigationButton,
1619
TabView,
1720
TabViewItem,
18-
VTemplate,
19-
android,
20-
ios
21+
transition,
22+
VTemplate
2123
}
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
export {
2+
transitionProps,
3+
extractTransitionData
4+
} from 'web/runtime/components/transition'
5+
6+
import Transition from 'web/runtime/components/transition'
7+
8+
export default Transition

platform/nativescript/runtime/modules/index.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,5 +2,6 @@ import attrs from './attrs'
22
import class_ from './class'
33
import events from './events'
44
import style from './style'
5+
import transition from './transition'
56

6-
export default [attrs, class_, events, style]
7+
export default [attrs, class_, events, style, transition]

platform/nativescript/runtime/modules/style.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@ function updateStyle(oldVnode, vnode) {
5353

5454
function toObject(arr) {
5555
const res = {}
56-
for (var i = 0; i < arr.length; i++) {
56+
for (let i = 0; i < arr.length; i++) {
5757
if (arr[i]) {
5858
extend(res, arr[i])
5959
}
Lines changed: 325 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,325 @@
1+
import { warn } from 'core/util/index'
2+
import { mergeVNodeHook } from 'core/vdom/helpers/index'
3+
import { activeInstance } from 'core/instance/lifecycle'
4+
5+
import { once, isDef, isUndef, isObject, toNumber } from 'shared/util'
6+
7+
import {
8+
nextFrame,
9+
resolveTransition,
10+
whenTransitionEnds,
11+
addTransitionClass,
12+
removeTransitionClass
13+
} from 'web/runtime/transition-util'
14+
15+
export function enter(vnode, toggleDisplay) {
16+
const el = vnode.elm
17+
18+
// call leave callback now
19+
if (isDef(el._leaveCb)) {
20+
el._leaveCb.cancelled = true
21+
el._leaveCb()
22+
}
23+
24+
const data = resolveTransition(vnode.data.transition)
25+
26+
if (isUndef(data)) {
27+
return
28+
}
29+
30+
/* istanbul ignore if */
31+
if (isDef(el._enterCb) || el.nodeType !== 1) {
32+
return
33+
}
34+
35+
const {
36+
css,
37+
type,
38+
enterClass,
39+
enterToClass,
40+
enterActiveClass,
41+
appearClass,
42+
appearToClass,
43+
appearActiveClass,
44+
beforeEnter,
45+
enter,
46+
afterEnter,
47+
enterCancelled,
48+
beforeAppear,
49+
appear,
50+
afterAppear,
51+
appearCancelled,
52+
duration
53+
} = data
54+
55+
// activeInstance will always be the <transition> component managing this
56+
// transition. One edge case to check is when the <transition> is placed
57+
// as the root node of a child component. In that case we need to check
58+
// <transition>'s parent for appear check.
59+
let context = activeInstance
60+
let transitionNode = activeInstance.$vnode
61+
while (transitionNode && transitionNode.parent) {
62+
transitionNode = transitionNode.parent
63+
context = transitionNode.context
64+
}
65+
66+
const isAppear = !context._isMounted || !vnode.isRootInsert
67+
68+
if (isAppear && !appear && appear !== '') {
69+
return
70+
}
71+
72+
const startClass = isAppear && appearClass ? appearClass : enterClass
73+
const activeClass =
74+
isAppear && appearActiveClass ? appearActiveClass : enterActiveClass
75+
const toClass = isAppear && appearToClass ? appearToClass : enterToClass
76+
77+
const beforeEnterHook = isAppear ? beforeAppear || beforeEnter : beforeEnter
78+
const enterHook = isAppear
79+
? typeof appear === 'function' ? appear : enter
80+
: enter
81+
const afterEnterHook = isAppear ? afterAppear || afterEnter : afterEnter
82+
const enterCancelledHook = isAppear
83+
? appearCancelled || enterCancelled
84+
: enterCancelled
85+
86+
const explicitEnterDuration = toNumber(
87+
isObject(duration) ? duration.enter : duration
88+
)
89+
90+
if (process.env.NODE_ENV !== 'production' && explicitEnterDuration != null) {
91+
checkDuration(explicitEnterDuration, 'enter', vnode)
92+
}
93+
94+
const expectsCSS = css !== false
95+
const userWantsControl = getHookArgumentsLength(enterHook)
96+
97+
const cb = (el._enterCb = once(() => {
98+
if (expectsCSS) {
99+
removeTransitionClass(el, toClass)
100+
removeTransitionClass(el, activeClass)
101+
}
102+
if (cb.cancelled) {
103+
if (expectsCSS) {
104+
removeTransitionClass(el, startClass)
105+
}
106+
enterCancelledHook && enterCancelledHook(el)
107+
} else {
108+
afterEnterHook && afterEnterHook(el)
109+
}
110+
el._enterCb = null
111+
}))
112+
113+
if (!vnode.data.show) {
114+
// remove pending leave element on enter by injecting an insert hook
115+
mergeVNodeHook(vnode, 'insert', () => {
116+
const parent = el.parentNode
117+
const pendingNode =
118+
parent && parent._pending && parent._pending[vnode.key]
119+
if (
120+
pendingNode &&
121+
pendingNode.tag === vnode.tag &&
122+
pendingNode.elm._leaveCb
123+
) {
124+
pendingNode.elm._leaveCb()
125+
}
126+
enterHook && enterHook(el, cb)
127+
})
128+
}
129+
130+
// start enter transition
131+
beforeEnterHook && beforeEnterHook(el)
132+
if (expectsCSS) {
133+
addTransitionClass(el, startClass)
134+
addTransitionClass(el, activeClass)
135+
nextFrame(() => {
136+
removeTransitionClass(el, startClass)
137+
if (!cb.cancelled) {
138+
addTransitionClass(el, toClass)
139+
if (!userWantsControl) {
140+
if (isValidDuration(explicitEnterDuration)) {
141+
setTimeout(cb, explicitEnterDuration)
142+
} else {
143+
//whenTransitionEnds(el, type, cb)
144+
}
145+
}
146+
}
147+
})
148+
}
149+
150+
if (vnode.data.show) {
151+
toggleDisplay && toggleDisplay()
152+
enterHook && enterHook(el, cb)
153+
}
154+
155+
if (!expectsCSS && !userWantsControl) {
156+
cb()
157+
}
158+
}
159+
160+
export function leave(vnode, rm) {
161+
const el = vnode.elm
162+
163+
// call enter callback now
164+
if (isDef(el._enterCb)) {
165+
el._enterCb.cancelled = true
166+
el._enterCb()
167+
}
168+
169+
const data = resolveTransition(vnode.data.transition)
170+
if (isUndef(data) || el.nodeType !== 1) {
171+
return rm()
172+
}
173+
174+
/* istanbul ignore if */
175+
if (isDef(el._leaveCb)) {
176+
return
177+
}
178+
179+
const {
180+
css,
181+
type,
182+
leaveClass,
183+
leaveToClass,
184+
leaveActiveClass,
185+
beforeLeave,
186+
leave,
187+
afterLeave,
188+
leaveCancelled,
189+
delayLeave,
190+
duration
191+
} = data
192+
193+
const expectsCSS = css !== false
194+
const userWantsControl = getHookArgumentsLength(leave)
195+
196+
const explicitLeaveDuration = toNumber(
197+
isObject(duration) ? duration.leave : duration
198+
)
199+
200+
if (process.env.NODE_ENV !== 'production' && isDef(explicitLeaveDuration)) {
201+
checkDuration(explicitLeaveDuration, 'leave', vnode)
202+
}
203+
204+
const cb = (el._leaveCb = once(() => {
205+
if (el.parentNode && el.parentNode._pending) {
206+
el.parentNode._pending[vnode.key] = null
207+
}
208+
if (expectsCSS) {
209+
removeTransitionClass(el, leaveToClass)
210+
removeTransitionClass(el, leaveActiveClass)
211+
}
212+
if (cb.cancelled) {
213+
if (expectsCSS) {
214+
removeTransitionClass(el, leaveClass)
215+
}
216+
leaveCancelled && leaveCancelled(el)
217+
} else {
218+
rm()
219+
afterLeave && afterLeave(el)
220+
}
221+
el._leaveCb = null
222+
}))
223+
224+
if (delayLeave) {
225+
delayLeave(performLeave)
226+
} else {
227+
performLeave()
228+
}
229+
230+
function performLeave() {
231+
// the delayed leave may have already been cancelled
232+
if (cb.cancelled) {
233+
return
234+
}
235+
// record leaving element
236+
if (!vnode.data.show) {
237+
;(el.parentNode._pending || (el.parentNode._pending = {}))[
238+
vnode.key
239+
] = vnode
240+
}
241+
beforeLeave && beforeLeave(el)
242+
if (expectsCSS) {
243+
addTransitionClass(el, leaveClass)
244+
addTransitionClass(el, leaveActiveClass)
245+
nextFrame(() => {
246+
removeTransitionClass(el, leaveClass)
247+
if (!cb.cancelled) {
248+
addTransitionClass(el, leaveToClass)
249+
if (!userWantsControl) {
250+
if (isValidDuration(explicitLeaveDuration)) {
251+
setTimeout(cb, explicitLeaveDuration)
252+
} else {
253+
//whenTransitionEnds(el, type, cb)
254+
}
255+
}
256+
}
257+
})
258+
}
259+
leave && leave(el, cb)
260+
if (!expectsCSS && !userWantsControl) {
261+
cb()
262+
}
263+
}
264+
}
265+
266+
// only used in dev mode
267+
function checkDuration(val, name, vnode) {
268+
if (typeof val !== 'number') {
269+
warn(
270+
`<transition> explicit ${name} duration is not a valid number - ` +
271+
`got ${JSON.stringify(val)}.`,
272+
vnode.context
273+
)
274+
} else if (isNaN(val)) {
275+
warn(
276+
`<transition> explicit ${name} duration is NaN - ` +
277+
'the duration expression might be incorrect.',
278+
vnode.context
279+
)
280+
}
281+
}
282+
283+
function isValidDuration(val) {
284+
return typeof val === 'number' && !isNaN(val)
285+
}
286+
287+
/**
288+
* Normaliz 10B8A e a transition hook's argument length. The hook may be:
289+
* - a merged hook (invoker) with the original in .fns
290+
* - a wrapped component method (check ._length)
291+
* - a plain function (.length)
292+
*/
293+
function getHookArgumentsLength(fn) {
294+
if (isUndef(fn)) {
295+
return false
296+
}
297+
const invokerFns = fn.fns
298+
if (isDef(invokerFns)) {
299+
// invoker
300+
return getHookArgumentsLength(
301+
Array.isArray(invokerFns) ? invokerFns[0] : invokerFns
302+
)
303+
} else {
304+
return (fn._length || fn.length) > 1
305+
}
306+
}
307+
308+
function _enter(_, vnode) {
309+
if (vnode.data.show !== true) {
310+
enter(vnode)
311+
}
312+
}
313+
314+
export default {
315+
create: _enter,
316+
activate: _enter,
317+
remove(vnode, rm) {
318+
/* istanbul ignore else */
319+
if (vnode.data.show !== true) {
320+
leave(vnode, rm)
321+
} else {
322+
rm()
323+
}
324+
}
325+
}

0 commit comments

Comments
 (0)
0