123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166 |
- /* @flow */
- import config from '../config'
- import VNode, { createEmptyVNode } from './vnode'
- import { createComponent } from './create-component'
- import { traverse } from '../observer/traverse'
- import {
- warn,
- isDef,
- isUndef,
- isTrue,
- isObject,
- isPrimitive,
- resolveAsset
- } from '../util/index'
- import {
- normalizeChildren,
- simpleNormalizeChildren
- } from './helpers/index'
- const SIMPLE_NORMALIZE = 1
- const ALWAYS_NORMALIZE = 2
- // wrapper function for providing a more flexible interface
- // without getting yelled at by flow
- export function createElement (
- context: Component,
- tag: any,
- data: any,
- children: any,
- normalizationType: any,
- alwaysNormalize: boolean
- ): VNode | Array<VNode> {
- if (Array.isArray(data) || isPrimitive(data)) {
- normalizationType = children
- children = data
- data = undefined
- }
- if (isTrue(alwaysNormalize)) {
- normalizationType = ALWAYS_NORMALIZE
- }
- return _createElement(context, tag, data, children, normalizationType)
- }
- export function _createElement (
- context: Component,
- tag?: string | Class<Component> | Function | Object,
- data?: VNodeData,
- children?: any,
- normalizationType?: number
- ): VNode | Array<VNode> {
- if (isDef(data) && isDef((data: any).__ob__)) {
- process.env.NODE_ENV !== 'production' && warn(
- `Avoid using observed data object as vnode data: ${JSON.stringify(data)}\n` +
- 'Always create fresh vnode data objects in each render!',
- context
- )
- return createEmptyVNode()
- }
- // object syntax in v-bind
- if (isDef(data) && isDef(data.is)) {
- tag = data.is
- }
- if (!tag) {
- // in case of component :is set to falsy value
- return createEmptyVNode()
- }
- // warn against non-primitive key
- if (process.env.NODE_ENV !== 'production' &&
- isDef(data) && isDef(data.key) && !isPrimitive(data.key)
- ) {
- if (!__WEEX__ || !('@binding' in data.key)) {
- warn(
- 'Avoid using non-primitive value as key, ' +
- 'use string/number value instead.',
- context
- )
- }
- }
- // support single function children as default scoped slot
- if (Array.isArray(children) &&
- typeof children[0] === 'function'
- ) {
- data = data || {}
- data.scopedSlots = { default: children[0] }
- children.length = 0
- }
- if (normalizationType === ALWAYS_NORMALIZE) {
- children = normalizeChildren(children)
- } else if (normalizationType === SIMPLE_NORMALIZE) {
- children = simpleNormalizeChildren(children)
- }
- let vnode, ns
- if (typeof tag === 'string') {
- let Ctor
- ns = (context.$vnode && context.$vnode.ns) || config.getTagNamespace(tag)
- if (config.isReservedTag(tag)) {
- // platform built-in elements
- if (process.env.NODE_ENV !== 'production' && isDef(data) && isDef(data.nativeOn)) {
- warn(
- `The .native modifier for v-on is only valid on components but it was used on <${tag}>.`,
- context
- )
- }
- vnode = new VNode(
- config.parsePlatformTagName(tag), data, children,
- undefined, undefined, context
- )
- } else if ((!data || !data.pre) && isDef(Ctor = resolveAsset(context.$options, 'components', tag))) {
- // component
- vnode = createComponent(Ctor, data, context, children, tag)
- } else {
- // unknown or unlisted namespaced elements
- // check at runtime because it may get assigned a namespace when its
- // parent normalizes children
- vnode = new VNode(
- tag, data, children,
- undefined, undefined, context
- )
- }
- } else {
- // direct component options / constructor
- vnode = createComponent(tag, data, context, children)
- }
- if (Array.isArray(vnode)) {
- return vnode
- } else if (isDef(vnode)) {
- if (isDef(ns)) applyNS(vnode, ns)
- if (isDef(data)) registerDeepBindings(data)
- return vnode
- } else {
- return createEmptyVNode()
- }
- }
- function applyNS (vnode, ns, force) {
- vnode.ns = ns
- if (vnode.tag === 'foreignObject') {
- // use default namespace inside foreignObject
- ns = undefined
- force = true
- }
- if (isDef(vnode.children)) {
- for (let i = 0, l = vnode.children.length; i < l; i++) {
- const child = vnode.children[i]
- if (isDef(child.tag) && (
- isUndef(child.ns) || (isTrue(force) && child.tag !== 'svg'))) {
- applyNS(child, ns, force)
- }
- }
- }
- }
- // ref #5318
- // necessary to ensure parent re-render when deep bindings like :style and
- // :class are used on slot nodes
- function registerDeepBindings (data) {
- if (isObject(data.style)) {
- traverse(data.style)
- }
- if (isObject(data.class)) {
- traverse(data.class)
- }
- }
|