create-element.js 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135
  1. /* @flow */
  2. import config from '../config'
  3. import VNode, { createEmptyVNode } from './vnode'
  4. import { createComponent } from './create-component'
  5. import {
  6. warn,
  7. isDef,
  8. isUndef,
  9. isTrue,
  10. isPrimitive,
  11. resolveAsset
  12. } from '../util/index'
  13. import {
  14. normalizeChildren,
  15. simpleNormalizeChildren
  16. } from './helpers/index'
  17. const SIMPLE_NORMALIZE = 1
  18. const ALWAYS_NORMALIZE = 2
  19. // wrapper function for providing a more flexible interface
  20. // without getting yelled at by flow
  21. export function createElement (
  22. context: Component,
  23. tag: any,
  24. data: any,
  25. children: any,
  26. normalizationType: any,
  27. alwaysNormalize: boolean
  28. ): VNode {
  29. if (Array.isArray(data) || isPrimitive(data)) {
  30. normalizationType = children
  31. children = data
  32. data = undefined
  33. }
  34. if (isTrue(alwaysNormalize)) {
  35. normalizationType = ALWAYS_NORMALIZE
  36. }
  37. return _createElement(context, tag, data, children, normalizationType)
  38. }
  39. export function _createElement (
  40. context: Component,
  41. tag?: string | Class<Component> | Function | Object,
  42. data?: VNodeData,
  43. children?: any,
  44. normalizationType?: number
  45. ): VNode {
  46. if (isDef(data) && isDef((data: any).__ob__)) {
  47. process.env.NODE_ENV !== 'production' && warn(
  48. `Avoid using observed data object as vnode data: ${JSON.stringify(data)}\n` +
  49. 'Always create fresh vnode data objects in each render!',
  50. context
  51. )
  52. return createEmptyVNode()
  53. }
  54. if (!tag) {
  55. // in case of component :is set to falsy value
  56. return createEmptyVNode()
  57. }
  58. // warn against non-primitive key
  59. if (process.env.NODE_ENV !== 'production' &&
  60. isDef(data) && isDef(data.key) && !isPrimitive(data.key)
  61. ) {
  62. warn(
  63. 'Avoid using non-primitive value as key, ' +
  64. 'use string/number value instead.',
  65. context
  66. )
  67. }
  68. // support single function children as default scoped slot
  69. if (Array.isArray(children) &&
  70. typeof children[0] === 'function'
  71. ) {
  72. data = data || {}
  73. data.scopedSlots = { default: children[0] }
  74. children.length = 0
  75. }
  76. if (normalizationType === ALWAYS_NORMALIZE) {
  77. children = normalizeChildren(children)
  78. } else if (normalizationType === SIMPLE_NORMALIZE) {
  79. children = simpleNormalizeChildren(children)
  80. }
  81. let vnode, ns
  82. if (typeof tag === 'string') {
  83. let Ctor
  84. ns = config.getTagNamespace(tag)
  85. if (config.isReservedTag(tag)) {
  86. // platform built-in elements
  87. vnode = new VNode(
  88. config.parsePlatformTagName(tag), data, children,
  89. undefined, undefined, context
  90. )
  91. } else if (isDef(Ctor = resolveAsset(context.$options, 'components', tag))) {
  92. // component
  93. vnode = createComponent(Ctor, data, context, children, tag)
  94. } else {
  95. // unknown or unlisted namespaced elements
  96. // check at runtime because it may get assigned a namespace when its
  97. // parent normalizes children
  98. vnode = new VNode(
  99. tag, data, children,
  100. undefined, undefined, context
  101. )
  102. }
  103. } else {
  104. // direct component options / constructor
  105. vnode = createComponent(tag, data, context, children)
  106. }
  107. if (isDef(vnode)) {
  108. if (ns) applyNS(vnode, ns)
  109. return vnode
  110. } else {
  111. return createEmptyVNode()
  112. }
  113. }
  114. function applyNS (vnode, ns) {
  115. vnode.ns = ns
  116. if (vnode.tag === 'foreignObject') {
  117. // use default namespace inside foreignObject
  118. return
  119. }
  120. if (isDef(vnode.children)) {
  121. for (let i = 0, l = vnode.children.length; i < l; i++) {
  122. const child = vnode.children[i]
  123. if (isDef(child.tag) && isUndef(child.ns)) {
  124. applyNS(child, ns)
  125. }
  126. }
  127. }
  128. }