transition.js 2.4 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283
  1. import { noop } from 'shared/util'
  2. import { warn, extend } from 'core/util/index'
  3. import { leave } from 'web/runtime/modules/transition'
  4. import { getRealChild } from 'core/vdom/helpers'
  5. export default {
  6. name: 'transition',
  7. props: {
  8. name: String,
  9. appear: Boolean,
  10. mode: String,
  11. enterClass: String,
  12. leaveClass: String,
  13. enterActiveClass: String,
  14. leaveActiveClass: String,
  15. appearClass: String,
  16. appearActiveClass: String
  17. },
  18. _abstract: true,
  19. render (h) {
  20. const children = this.$slots.default && this.$slots.default.filter(c => c.tag)
  21. if (!children || !children.length) {
  22. return
  23. }
  24. if (process.env.NODE_ENV !== 'production' && children.length > 1) {
  25. warn(
  26. '<transition> can only be used on a single element. Use ' +
  27. '<transition-group> for lists.'
  28. )
  29. }
  30. const rawChild = children[0]
  31. // if this is a component root node and the compoennt's
  32. // parent container node also has transition, skip.
  33. if (this.$vnode.parent && this.$vnode.parent.data.transition) {
  34. return rawChild
  35. }
  36. const child = getRealChild(rawChild)
  37. child.key = child.key || `__v${child.tag + this._uid}__`
  38. const data = (child.data || (child.data = {})).transition = { context: this }
  39. for (const key in this.$options.propsData) {
  40. data[key] = this[key]
  41. }
  42. const mode = this.mode
  43. const oldRawChild = this._vnode
  44. const oldChild = getRealChild(oldRawChild)
  45. if (mode && oldChild && oldChild.data && oldChild.key !== child.key) {
  46. if (mode === 'out-in') {
  47. // return old node
  48. // and queue an update when the leave finishes
  49. if (!oldChild.elm._leaveCb) {
  50. leave(oldChild, () => {
  51. oldRawChild.data.left = true
  52. this.$forceUpdate()
  53. })
  54. }
  55. return oldRawChild.data.left ? rawChild : oldRawChild
  56. } else if (mode === 'in-out') {
  57. let delayedLeave
  58. const performLeave = () => { delayedLeave() }
  59. extend(child.data.transition, {
  60. afterEnter: performLeave,
  61. enterCancelled: performLeave
  62. })
  63. extend(oldChild.data.transition, {
  64. delayLeave: leave => {
  65. delayedLeave = leave
  66. },
  67. leaveCancelled: () => {
  68. delayedLeave = noop
  69. }
  70. })
  71. } else if (process.env.NODE_ENV !== 'production') {
  72. warn('invalid <transition> mode: ' + mode)
  73. }
  74. }
  75. return rawChild
  76. }
  77. }