Transition.ts 2.1 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980
  1. import {
  2. type CompilerError,
  3. type ComponentNode,
  4. ElementTypes,
  5. type IfBranchNode,
  6. type NodeTransform,
  7. NodeTypes,
  8. isCommentOrWhitespace,
  9. } from '@vue/compiler-core'
  10. import { TRANSITION } from '../runtimeHelpers'
  11. import { DOMErrorCodes, createDOMCompilerError } from '../errors'
  12. export const transformTransition: NodeTransform = (node, context) => {
  13. if (
  14. node.type === NodeTypes.ELEMENT &&
  15. node.tagType === ElementTypes.COMPONENT
  16. ) {
  17. const component = context.isBuiltInComponent(node.tag)
  18. if (component === TRANSITION) {
  19. return postTransformTransition(node, context.onError)
  20. }
  21. }
  22. }
  23. export function postTransformTransition(
  24. node: ComponentNode,
  25. onError: (error: CompilerError) => void,
  26. hasMultipleChildren: (
  27. node: ComponentNode,
  28. ) => boolean = defaultHasMultipleChildren,
  29. ): () => void {
  30. return () => {
  31. if (!node.children.length) {
  32. return
  33. }
  34. if (hasMultipleChildren(node)) {
  35. onError(
  36. createDOMCompilerError(DOMErrorCodes.X_TRANSITION_INVALID_CHILDREN, {
  37. start: node.children[0].loc.start,
  38. end: node.children[node.children.length - 1].loc.end,
  39. source: '',
  40. }),
  41. )
  42. }
  43. // check if it's a single child w/ v-show
  44. // if yes, inject "persisted: true" to the transition props
  45. const child = node.children[0]
  46. if (child.type === NodeTypes.ELEMENT) {
  47. for (const p of child.props) {
  48. if (p.type === NodeTypes.DIRECTIVE && p.name === 'show') {
  49. node.props.push({
  50. type: NodeTypes.ATTRIBUTE,
  51. name: 'persisted',
  52. nameLoc: node.loc,
  53. value: undefined,
  54. loc: node.loc,
  55. })
  56. }
  57. }
  58. }
  59. }
  60. }
  61. function defaultHasMultipleChildren(
  62. node: ComponentNode | IfBranchNode,
  63. ): boolean {
  64. // filter out potential comment nodes (#1352) and whitespace (#4637)
  65. const children = (node.children = node.children.filter(
  66. c => !isCommentOrWhitespace(c),
  67. ))
  68. const child = children[0]
  69. return (
  70. children.length !== 1 ||
  71. child.type === NodeTypes.FOR ||
  72. (child.type === NodeTypes.IF &&
  73. child.branches.some(defaultHasMultipleChildren))
  74. )
  75. }