normalize-children.js 2.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869
  1. /* @flow */
  2. import VNode, { createTextVNode } from 'core/vdom/vnode'
  3. import { isFalse, 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 normalizeArrayChildren (children: any, nestedIndex?: string): Array<VNode> {
  35. const res = []
  36. let i, c, last
  37. for (i = 0; i < children.length; i++) {
  38. c = children[i]
  39. if (isUndef(c) || typeof c === 'boolean') continue
  40. last = res[res.length - 1]
  41. // nested
  42. if (Array.isArray(c)) {
  43. res.push.apply(res, normalizeArrayChildren(c, `${nestedIndex || ''}_${i}`))
  44. } else if (isPrimitive(c)) {
  45. if (isDef(last) && isDef(last.text)) {
  46. last.text += String(c)
  47. } else if (c !== '') {
  48. // convert primitive to vnode
  49. res.push(createTextVNode(c))
  50. }
  51. } else {
  52. if (isFalse(c.isComment) && isDef(c.text) && isDef(last) && isFalse(last.isComment) && isDef(last.text)) {
  53. res[res.length - 1] = createTextVNode(last.text + c.text)
  54. } else {
  55. // default key for nested array children (likely generated by v-for)
  56. if (isDef(c.tag) && isUndef(c.key) && isDef(nestedIndex)) {
  57. c.key = `__vlist${nestedIndex}_${i}__`
  58. }
  59. res.push(c)
  60. }
  61. }
  62. }
  63. return res
  64. }