0e600caa22425bb7d30d3ef6e58a28710e3c0058492ca673bbd14462f820ae469b051914eb172df407310f43f8fa7e8e756b595c682463b4b9291b81a5d279 3.2 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889
  1. /* @flow */
  2. import VNode, { createTextVNode } from 'core/vdom/vnode'
  3. import { isFalse, isTrue, isDef, isUndef, isPrimitive } from 'shared/util'
  4. // The template compiler attempts to minimize the need for normalization by
  5. // statically analyzing the template at compile time.
  6. //
  7. // For plain HTML markup, normalization can be completely skipped because the
  8. // generated render function is guaranteed to return Array<VNode>. There are
  9. // two cases where extra normalization is needed:
  10. // 1. When the children contains components - because a functional component
  11. // may return an Array instead of a single root. In this case, just a simple
  12. // normalization is needed - if any child is an Array, we flatten the whole
  13. // thing with Array.prototype.concat. It is guaranteed to be only 1-level deep
  14. // because functional components already normalize their own children.
  15. export function simpleNormalizeChildren (children: any) {
  16. for (let i = 0; i < children.length; i++) {
  17. if (Array.isArray(children[i])) {
  18. return Array.prototype.concat.apply([], children)
  19. }
  20. }
  21. return children
  22. }
  23. // 2. When the children contains constructs that always generated nested Arrays,
  24. // e.g. <template>, <slot>, v-for, or when the children is provided by user
  25. // with hand-written render functions / JSX. In such cases a full normalization
  26. // is needed to cater to all possible types of children values.
  27. export function normalizeChildren (children: any): ?Array<VNode> {
  28. return isPrimitive(children)
  29. ? [createTextVNode(children)]
  30. : Array.isArray(children)
  31. ? normalizeArrayChildren(children)
  32. : undefined
  33. }
  34. function isTextNode (node): boolean {
  35. return isDef(node) && isDef(node.text) && isFalse(node.isComment)
  36. }
  37. function normalizeArrayChildren (children: any, nestedIndex?: string): Array<VNode> {
  38. const res = []
  39. let i, c, lastIndex, last
  40. for (i = 0; i < children.length; i++) {
  41. c = children[i]
  42. if (isUndef(c) || typeof c === 'boolean') continue
  43. lastIndex = res.length - 1
  44. last = res[lastIndex]
  45. // nested
  46. if (Array.isArray(c)) {
  47. if (c.length > 0) {
  48. c = normalizeArrayChildren(c, `${nestedIndex || ''}_${i}`)
  49. // merge adjacent text nodes
  50. if (isTextNode(c[0]) && isTextNode(last)) {
  51. res[lastIndex] = createTextVNode(last.text + (c[0]: any).text)
  52. c.shift()
  53. }
  54. res.push.apply(res, c)
  55. }
  56. } else if (isPrimitive(c)) {
  57. if (isTextNode(last)) {
  58. // merge adjacent text nodes
  59. // this is necessary for SSR hydration because text nodes are
  60. // essentially merged when rendered to HTML strings
  61. res[lastIndex] = createTextVNode(last.text + c)
  62. } else if (c !== '') {
  63. // convert primitive to vnode
  64. res.push(createTextVNode(c))
  65. }
  66. } else {
  67. if (isTextNode(c) && isTextNode(last)) {
  68. // merge adjacent text nodes
  69. res[lastIndex] = createTextVNode(last.text + c.text)
  70. } else {
  71. // default key for nested array children (likely generated by v-for)
  72. if (isTrue(children._isVList) &&
  73. isDef(c.tag) &&
  74. isUndef(c.key) &&
  75. isDef(nestedIndex)) {
  76. c.key = `__vlist${nestedIndex}_${i}__`
  77. }
  78. res.push(c)
  79. }
  80. }
  81. }
  82. return res
  83. }