f923b3ddb364202bd3672b2511030fcacc3ad2c7f4025ab8f9cb3848633de2db11f539213d6155b5c020eb891ad09cc83597c913140f73fd00cdedccfdcbe0 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148
  1. import { warn, extend } from 'core/util/index'
  2. import { transitionProps, extractTransitionData } from './transition'
  3. const props = extend({
  4. tag: String,
  5. moveClass: String
  6. }, transitionProps)
  7. delete props.mode
  8. export default {
  9. props,
  10. created () {
  11. const dom = this.$requireWeexModule('dom')
  12. this.getPosition = el => new Promise((resolve, reject) => {
  13. dom.getComponentRect(el.ref, res => {
  14. if (!res.result) {
  15. reject(new Error(`failed to get rect for element: ${el.tag}`))
  16. } else {
  17. resolve(res.size)
  18. }
  19. })
  20. })
  21. const animation = this.$requireWeexModule('animation')
  22. this.animate = (el, options) => new Promise(resolve => {
  23. animation.transition(el.ref, options, resolve)
  24. })
  25. },
  26. render (h) {
  27. const tag = this.tag || this.$vnode.data.tag || 'span'
  28. const map = Object.create(null)
  29. const prevChildren = this.prevChildren = this.children
  30. const rawChildren = this.$slots.default || []
  31. const children = this.children = []
  32. const transitionData = extractTransitionData(this)
  33. for (let i = 0; i < rawChildren.length; i++) {
  34. const c = rawChildren[i]
  35. if (c.tag) {
  36. if (c.key != null && String(c.key).indexOf('__vlist') !== 0) {
  37. children.push(c)
  38. map[c.key] = c
  39. ;(c.data || (c.data = {})).transition = transitionData
  40. } else if (process.env.NODE_ENV !== 'production') {
  41. const opts = c.componentOptions
  42. const name = opts
  43. ? (opts.Ctor.options.name || opts.tag)
  44. : c.tag
  45. warn(`<transition-group> children must be keyed: <${name}>`)
  46. }
  47. }
  48. }
  49. if (prevChildren) {
  50. const kept = []
  51. const removed = []
  52. prevChildren.forEach(c => {
  53. c.data.transition = transitionData
  54. // TODO: record before patch positions
  55. if (map[c.key]) {
  56. kept.push(c)
  57. } else {
  58. removed.push(c)
  59. }
  60. })
  61. this.kept = h(tag, null, kept)
  62. this.removed = removed
  63. }
  64. return h(tag, null, children)
  65. },
  66. beforeUpdate () {
  67. // force removing pass
  68. this.__patch__(
  69. this._vnode,
  70. this.kept,
  71. false, // hydrating
  72. true // removeOnly (!important, avoids unnecessary moves)
  73. )
  74. this._vnode = this.kept
  75. },
  76. updated () {
  77. const children = this.prevChildren
  78. const moveClass = this.moveClass || ((this.name || 'v') + '-move')
  79. const moveData = children.length && this.getMoveData(children[0].context, moveClass)
  80. if (!moveData) {
  81. return
  82. }
  83. // TODO: finish implementing move animations once
  84. // we have access to sync getComponentRect()
  85. // children.forEach(callPendingCbs)
  86. // Promise.all(children.map(c => {
  87. // const oldPos = c.data.pos
  88. // const newPos = c.data.newPos
  89. // const dx = oldPos.left - newPos.left
  90. // const dy = oldPos.top - newPos.top
  91. // if (dx || dy) {
  92. // c.data.moved = true
  93. // return this.animate(c.elm, {
  94. // styles: {
  95. // transform: `translate(${dx}px,${dy}px)`
  96. // }
  97. // })
  98. // }
  99. // })).then(() => {
  100. // children.forEach(c => {
  101. // if (c.data.moved) {
  102. // this.animate(c.elm, {
  103. // styles: {
  104. // transform: ''
  105. // },
  106. // duration: moveData.duration || 0,
  107. // delay: moveData.delay || 0,
  108. // timingFunction: moveData.timingFunction || 'linear'
  109. // })
  110. // }
  111. // })
  112. // })
  113. },
  114. methods: {
  115. getMoveData (context, moveClass) {
  116. const stylesheet = context.$options.style || {}
  117. return stylesheet['@TRANSITION'] && stylesheet['@TRANSITION'][moveClass]
  118. }
  119. }
  120. }
  121. // function callPendingCbs (c) {
  122. // /* istanbul ignore if */
  123. // if (c.elm._moveCb) {
  124. // c.elm._moveCb()
  125. // }
  126. // /* istanbul ignore if */
  127. // if (c.elm._enterCb) {
  128. // c.elm._enterCb()
  129. // }
  130. // }