Evan You
8 years ago
4 changed files with 160 additions and 3 deletions
@ -1,5 +1,7 @@ |
|||
import Transition from 'web/runtime/components/transition' |
|||
import Transition from './transition' |
|||
import TransitionGroup from './transition-group' |
|||
|
|||
export default { |
|||
Transition |
|||
Transition, |
|||
TransitionGroup |
|||
} |
|||
|
@ -0,0 +1,151 @@ |
|||
import { warn, extend } from 'core/util/index' |
|||
import { transitionProps, extractTransitionData } from './transition' |
|||
|
|||
const props = extend({ |
|||
tag: String, |
|||
moveClass: String |
|||
}, transitionProps) |
|||
|
|||
delete props.mode |
|||
|
|||
export default { |
|||
props, |
|||
|
|||
created () { |
|||
const dom = this._requireWeexModule('dom') |
|||
this.getPosition = el => new Promise((resolve, reject) => { |
|||
dom.getComponentRect(el.ref, res => { |
|||
if (!res.result) { |
|||
reject(new Error(`failed to get rect for element: ${el.tag}`)) |
|||
} else { |
|||
resolve(res.size) |
|||
} |
|||
}) |
|||
}) |
|||
|
|||
const animation = this._requireWeexModule('animation') |
|||
this.animate = (el, options) => new Promise(resolve => { |
|||
animation.transition(el.ref, options, resolve) |
|||
}) |
|||
}, |
|||
|
|||
render (h) { |
|||
const tag = this.tag || this.$vnode.data.tag || 'span' |
|||
const map = Object.create(null) |
|||
const prevChildren = this.prevChildren = this.children |
|||
const rawChildren = this.$slots.default || [] |
|||
const children = this.children = [] |
|||
const transitionData = extractTransitionData(this) |
|||
|
|||
for (let i = 0; i < rawChildren.length; i++) { |
|||
const c = rawChildren[i] |
|||
if (c.tag) { |
|||
if (c.key != null && String(c.key).indexOf('__vlist') !== 0) { |
|||
children.push(c) |
|||
map[c.key] = c |
|||
;(c.data || (c.data = {})).transition = transitionData |
|||
} else if (process.env.NODE_ENV !== 'production') { |
|||
const opts = c.componentOptions |
|||
const name = opts |
|||
? (opts.Ctor.options.name || opts.tag) |
|||
: c.tag |
|||
warn(`<transition-group> children must be keyed: <${name}>`) |
|||
} |
|||
} |
|||
} |
|||
|
|||
if (prevChildren) { |
|||
const kept = [] |
|||
const removed = [] |
|||
const positionPromises = [] |
|||
prevChildren.forEach(c => { |
|||
c.data.transition = transitionData |
|||
positionPromises.push(this.getPosition(c.elm).then(pos => { |
|||
c.data.pos = pos |
|||
})) |
|||
if (map[c.key]) { |
|||
kept.push(c) |
|||
} else { |
|||
removed.push(c) |
|||
} |
|||
}) |
|||
this.kept = h(tag, null, kept) |
|||
this.removed = removed |
|||
this.pendingPositions = Promise.all(positionPromises) |
|||
} |
|||
|
|||
return h(tag, null, children) |
|||
}, |
|||
|
|||
beforeUpdate () { |
|||
// force removing pass
|
|||
this.__patch__( |
|||
this._vnode, |
|||
this.kept, |
|||
false, // hydrating
|
|||
true // removeOnly (!important, avoids unnecessary moves)
|
|||
) |
|||
this._vnode = this.kept |
|||
}, |
|||
|
|||
updated () { |
|||
const children = this.prevChildren |
|||
const moveClass = this.moveClass || ((this.name || 'v') + '-move') |
|||
const moveData = children.length && this.getMoveData(children[0].context, moveClass) |
|||
if (!moveData) { |
|||
return |
|||
} |
|||
|
|||
children.forEach(callPendingCbs) |
|||
this.pendingPositions.then(() => Promise.all(children.map(c => { |
|||
// record new position
|
|||
return this.getPosition(c.elm).then(pos => { |
|||
c.data.newPos = pos |
|||
}) |
|||
}))).then(() => Promise.all(children.map(c => { |
|||
const oldPos = c.data.pos |
|||
const newPos = c.data.newPos |
|||
const dx = oldPos.left - newPos.left |
|||
const dy = oldPos.top - newPos.top |
|||
if (dx || dy) { |
|||
c.data.moved = true |
|||
return this.animate(c.elm, { |
|||
styles: { |
|||
transform: `translate(${dx}px,${dy}px)` |
|||
} |
|||
}) |
|||
} |
|||
}))).then(() => { |
|||
children.forEach(c => { |
|||
if (c.data.moved) { |
|||
this.animate(c.elm, { |
|||
styles: { |
|||
transform: '' |
|||
}, |
|||
duration: moveData.duration || 0, |
|||
delay: moveData.delay || 0, |
|||
timingFunction: moveData.timingFunction || 'linear' |
|||
}) |
|||
} |
|||
}) |
|||
}) |
|||
}, |
|||
|
|||
methods: { |
|||
getMoveData (context, moveClass) { |
|||
const stylesheet = context.$options.style || {} |
|||
return stylesheet['@TRANSITION'] && stylesheet['@TRANSITION'][moveClass] |
|||
} |
|||
} |
|||
} |
|||
|
|||
function callPendingCbs (c) { |
|||
/* istanbul ignore if */ |
|||
if (c.elm._moveCb) { |
|||
c.elm._moveCb() |
|||
} |
|||
/* istanbul ignore if */ |
|||
if (c.elm._enterCb) { |
|||
c.elm._enterCb() |
|||
} |
|||
} |
@ -0,0 +1,2 @@ |
|||
// reuse same transition component logic from web
|
|||
export * from 'web/runtime/components/transition' |
Loading…
Reference in new issue