|
|
@@ -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()
|
|
|
+ }
|
|
|
+}
|