Просмотр исходного кода

[weex] wip: experimenting with transition-group

Evan You 9 лет назад
Родитель
Сommit
b88d3ca82c

+ 4 - 2
src/platforms/weex/runtime/components/index.js

@@ -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
 }

+ 151 - 0
src/platforms/weex/runtime/components/transition-group.js

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

+ 2 - 0
src/platforms/weex/runtime/components/transition.js

@@ -0,0 +1,2 @@
+// reuse same transition component logic from web
+export * from 'web/runtime/components/transition'

+ 3 - 1
src/platforms/weex/runtime/modules/transition.js

@@ -1,3 +1,4 @@
+import { warn } from 'core/util/debug'
 import { extend, once, noop } from 'shared/util'
 import { activeInstance } from 'core/instance/lifecycle'
 import { resolveTransition } from 'web/runtime/transition-util'
@@ -233,11 +234,12 @@ function getEnterTargetState (el, stylesheet, startClass, endClass, activeClass,
     for (const key in startState) {
       targetState[key] = el.style[key]
       if (
+        process.env.NODE_ENV !== 'production' &&
         targetState[key] == null &&
         (!activeState || activeState[key] == null) &&
         (!endState || endState[key] == null)
       ) {
-        console.log(
+        warn(
           `transition property "${key}" is declared in enter starting class (.${startClass}), ` +
           `but not declared anywhere in enter ending class (.${endClass}), ` +
           `enter active cass (.${activeClass}) or the element's default styling. ` +