aboutsummaryrefslogtreecommitdiff
path: root/node_modules/vue/src/core/vdom
diff options
context:
space:
mode:
authorruki <waruqi@gmail.com>2018-11-08 00:38:48 +0800
committerruki <waruqi@gmail.com>2018-11-07 21:53:09 +0800
commit26105034da4fcce7ac883c899d781f016559310d (patch)
treec459a5dc4e3aa0972d9919033ece511ce76dd129 /node_modules/vue/src/core/vdom
parent2c77f00f1a7ecb6c8192f9c16d3b2001b254a107 (diff)
downloadxmake-docs-26105034da4fcce7ac883c899d781f016559310d.tar.gz
xmake-docs-26105034da4fcce7ac883c899d781f016559310d.zip
switch to vuepress
Diffstat (limited to 'node_modules/vue/src/core/vdom')
-rw-r--r--node_modules/vue/src/core/vdom/create-component.js257
-rw-r--r--node_modules/vue/src/core/vdom/create-element.js160
-rw-r--r--node_modules/vue/src/core/vdom/create-functional-component.js136
-rw-r--r--node_modules/vue/src/core/vdom/helpers/extract-props.js75
-rw-r--r--node_modules/vue/src/core/vdom/helpers/get-first-component-child.js15
-rw-r--r--node_modules/vue/src/core/vdom/helpers/index.js9
-rw-r--r--node_modules/vue/src/core/vdom/helpers/is-async-placeholder.js5
-rw-r--r--node_modules/vue/src/core/vdom/helpers/merge-hook.js38
-rw-r--r--node_modules/vue/src/core/vdom/helpers/normalize-children.js89
-rw-r--r--node_modules/vue/src/core/vdom/helpers/resolve-async-component.js140
-rw-r--r--node_modules/vue/src/core/vdom/helpers/update-listeners.js83
-rw-r--r--node_modules/vue/src/core/vdom/modules/directives.js119
-rw-r--r--node_modules/vue/src/core/vdom/modules/index.js7
-rw-r--r--node_modules/vue/src/core/vdom/modules/ref.js45
-rw-r--r--node_modules/vue/src/core/vdom/patch.js787
-rw-r--r--node_modules/vue/src/core/vdom/vnode.js108
16 files changed, 2073 insertions, 0 deletions
diff --git a/node_modules/vue/src/core/vdom/create-component.js b/node_modules/vue/src/core/vdom/create-component.js
new file mode 100644
index 00000000..89578224
--- /dev/null
+++ b/node_modules/vue/src/core/vdom/create-component.js
@@ -0,0 +1,257 @@
+/* @flow */
+
+import VNode from './vnode'
+import { resolveConstructorOptions } from 'core/instance/init'
+import { queueActivatedComponent } from 'core/observer/scheduler'
+import { createFunctionalComponent } from './create-functional-component'
+
+import {
+ warn,
+ isDef,
+ isUndef,
+ isTrue,
+ isObject
+} from '../util/index'
+
+import {
+ resolveAsyncComponent,
+ createAsyncPlaceholder,
+ extractPropsFromVNodeData
+} from './helpers/index'
+
+import {
+ callHook,
+ activeInstance,
+ updateChildComponent,
+ activateChildComponent,
+ deactivateChildComponent
+} from '../instance/lifecycle'
+
+import {
+ isRecyclableComponent,
+ renderRecyclableComponentTemplate
+} from 'weex/runtime/recycle-list/render-component-template'
+
+// inline hooks to be invoked on component VNodes during patch
+const componentVNodeHooks = {
+ init (
+ vnode: VNodeWithData,
+ hydrating: boolean,
+ parentElm: ?Node,
+ refElm: ?Node
+ ): ?boolean {
+ if (
+ vnode.componentInstance &&
+ !vnode.componentInstance._isDestroyed &&
+ vnode.data.keepAlive
+ ) {
+ // kept-alive components, treat as a patch
+ const mountedNode: any = vnode // work around flow
+ componentVNodeHooks.prepatch(mountedNode, mountedNode)
+ } else {
+ const child = vnode.componentInstance = createComponentInstanceForVnode(
+ vnode,
+ activeInstance,
+ parentElm,
+ refElm
+ )
+ child.$mount(hydrating ? vnode.elm : undefined, hydrating)
+ }
+ },
+
+ prepatch (oldVnode: MountedComponentVNode, vnode: MountedComponentVNode) {
+ const options = vnode.componentOptions
+ const child = vnode.componentInstance = oldVnode.componentInstance
+ updateChildComponent(
+ child,
+ options.propsData, // updated props
+ options.listeners, // updated listeners
+ vnode, // new parent vnode
+ options.children // new children
+ )
+ },
+
+ insert (vnode: MountedComponentVNode) {
+ const { context, componentInstance } = vnode
+ if (!componentInstance._isMounted) {
+ componentInstance._isMounted = true
+ callHook(componentInstance, 'mounted')
+ }
+ if (vnode.data.keepAlive) {
+ if (context._isMounted) {
+ // vue-router#1212
+ // During updates, a kept-alive component's child components may
+ // change, so directly walking the tree here may call activated hooks
+ // on incorrect children. Instead we push them into a queue which will
+ // be processed after the whole patch process ended.
+ queueActivatedComponent(componentInstance)
+ } else {
+ activateChildComponent(componentInstance, true /* direct */)
+ }
+ }
+ },
+
+ destroy (vnode: MountedComponentVNode) {
+ const { componentInstance } = vnode
+ if (!componentInstance._isDestroyed) {
+ if (!vnode.data.keepAlive) {
+ componentInstance.$destroy()
+ } else {
+ deactivateChildComponent(componentInstance, true /* direct */)
+ }
+ }
+ }
+}
+
+const hooksToMerge = Object.keys(componentVNodeHooks)
+
+export function createComponent (
+ Ctor: Class<Component> | Function | Object | void,
+ data: ?VNodeData,
+ context: Component,
+ children: ?Array<VNode>,
+ tag?: string
+): VNode | Array<VNode> | void {
+ if (isUndef(Ctor)) {
+ return
+ }
+
+ const baseCtor = context.$options._base
+
+ // plain options object: turn it into a constructor
+ if (isObject(Ctor)) {
+ Ctor = baseCtor.extend(Ctor)
+ }
+
+ // if at this stage it's not a constructor or an async component factory,
+ // reject.
+ if (typeof Ctor !== 'function') {
+ if (process.env.NODE_ENV !== 'production') {
+ warn(`Invalid Component definition: ${String(Ctor)}`, context)
+ }
+ return
+ }
+
+ // async component
+ let asyncFactory
+ if (isUndef(Ctor.cid)) {
+ asyncFactory = Ctor
+ Ctor = resolveAsyncComponent(asyncFactory, baseCtor, context)
+ if (Ctor === undefined) {
+ // return a placeholder node for async component, which is rendered
+ // as a comment node but preserves all the raw information for the node.
+ // the information will be used for async server-rendering and hydration.
+ return createAsyncPlaceholder(
+ asyncFactory,
+ data,
+ context,
+ children,
+ tag
+ )
+ }
+ }
+
+ data = data || {}
+
+ // resolve constructor options in case global mixins are applied after
+ // component constructor creation
+ resolveConstructorOptions(Ctor)
+
+ // transform component v-model data into props & events
+ if (isDef(data.model)) {
+ transformModel(Ctor.options, data)
+ }
+
+ // extract props
+ const propsData = extractPropsFromVNodeData(data, Ctor, tag)
+
+ // functional component
+ if (isTrue(Ctor.options.functional)) {
+ return createFunctionalComponent(Ctor, propsData, data, context, children)
+ }
+
+ // extract listeners, since these needs to be treated as
+ // child component listeners instead of DOM listeners
+ const listeners = data.on
+ // replace with listeners with .native modifier
+ // so it gets processed during parent component patch.
+ data.on = data.nativeOn
+
+ if (isTrue(Ctor.options.abstract)) {
+ // abstract components do not keep anything
+ // other than props & listeners & slot
+
+ // work around flow
+ const slot = data.slot
+ data = {}
+ if (slot) {
+ data.slot = slot
+ }
+ }
+
+ // install component management hooks onto the placeholder node
+ installComponentHooks(data)
+
+ // return a placeholder vnode
+ const name = Ctor.options.name || tag
+ const vnode = new VNode(
+ `vue-component-${Ctor.cid}${name ? `-${name}` : ''}`,
+ data, undefined, undefined, undefined, context,
+ { Ctor, propsData, listeners, tag, children },
+ asyncFactory
+ )
+
+ // Weex specific: invoke recycle-list optimized @render function for
+ // extracting cell-slot template.
+ // https://github.com/Hanks10100/weex-native-directive/tree/master/component
+ /* istanbul ignore if */
+ if (__WEEX__ && isRecyclableComponent(vnode)) {
+ return renderRecyclableComponentTemplate(vnode)
+ }
+
+ return vnode
+}
+
+export function createComponentInstanceForVnode (
+ vnode: any, // we know it's MountedComponentVNode but flow doesn't
+ parent: any, // activeInstance in lifecycle state
+ parentElm?: ?Node,
+ refElm?: ?Node
+): Component {
+ const options: InternalComponentOptions = {
+ _isComponent: true,
+ parent,
+ _parentVnode: vnode,
+ _parentElm: parentElm || null,
+ _refElm: refElm || null
+ }
+ // check inline-template render functions
+ const inlineTemplate = vnode.data.inlineTemplate
+ if (isDef(inlineTemplate)) {
+ options.render = inlineTemplate.render
+ options.staticRenderFns = inlineTemplate.staticRenderFns
+ }
+ return new vnode.componentOptions.Ctor(options)
+}
+
+function installComponentHooks (data: VNodeData) {
+ const hooks = data.hook || (data.hook = {})
+ for (let i = 0; i < hooksToMerge.length; i++) {
+ const key = hooksToMerge[i]
+ hooks[key] = componentVNodeHooks[key]
+ }
+}
+
+// transform component v-model info (value and callback) into
+// prop and event handler respectively.
+function transformModel (options, data: any) {
+ const prop = (options.model && options.model.prop) || 'value'
+ const event = (options.model && options.model.event) || 'input'
+ ;(data.props || (data.props = {}))[prop] = data.model.value
+ const on = data.on || (data.on = {})
+ if (isDef(on[event])) {
+ on[event] = [data.model.callback].concat(on[event])
+ } else {
+ on[event] = data.model.callback
+ }
+}
diff --git a/node_modules/vue/src/core/vdom/create-element.js b/node_modules/vue/src/core/vdom/create-element.js
new file mode 100644
index 00000000..c5cde2c6
--- /dev/null
+++ b/node_modules/vue/src/core/vdom/create-element.js
@@ -0,0 +1,160 @@
+/* @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
+ vnode = new VNode(
+ config.parsePlatformTagName(tag), data, children,
+ undefined, undefined, context
+ )
+ } else if (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)
+ }
+}
diff --git a/node_modules/vue/src/core/vdom/create-functional-component.js b/node_modules/vue/src/core/vdom/create-functional-component.js
new file mode 100644
index 00000000..efed801d
--- /dev/null
+++ b/node_modules/vue/src/core/vdom/create-functional-component.js
@@ -0,0 +1,136 @@
+/* @flow */
+
+import VNode, { cloneVNode } from './vnode'
+import { createElement } from './create-element'
+import { resolveInject } from '../instance/inject'
+import { normalizeChildren } from '../vdom/helpers/normalize-children'
+import { resolveSlots } from '../instance/render-helpers/resolve-slots'
+import { installRenderHelpers } from '../instance/render-helpers/index'
+
+import {
+ isDef,
+ isTrue,
+ hasOwn,
+ camelize,
+ emptyObject,
+ validateProp
+} from '../util/index'
+
+export function FunctionalRenderContext (
+ data: VNodeData,
+ props: Object,
+ children: ?Array<VNode>,
+ parent: Component,
+ Ctor: Class<Component>
+) {
+ const options = Ctor.options
+ // ensure the createElement function in functional components
+ // gets a unique context - this is necessary for correct named slot check
+ let contextVm
+ if (hasOwn(parent, '_uid')) {
+ contextVm = Object.create(parent)
+ // $flow-disable-line
+ contextVm._original = parent
+ } else {
+ // the context vm passed in is a functional context as well.
+ // in this case we want to make sure we are able to get a hold to the
+ // real context instance.
+ contextVm = parent
+ // $flow-disable-line
+ parent = parent._original
+ }
+ const isCompiled = isTrue(options._compiled)
+ const needNormalization = !isCompiled
+
+ this.data = data
+ this.props = props
+ this.children = children
+ this.parent = parent
+ this.listeners = data.on || emptyObject
+ this.injections = resolveInject(options.inject, parent)
+ this.slots = () => resolveSlots(children, parent)
+
+ // support for compiled functional template
+ if (isCompiled) {
+ // exposing $options for renderStatic()
+ this.$options = options
+ // pre-resolve slots for renderSlot()
+ this.$slots = this.slots()
+ this.$scopedSlots = data.scopedSlots || emptyObject
+ }
+
+ if (options._scopeId) {
+ this._c = (a, b, c, d) => {
+ const vnode = createElement(contextVm, a, b, c, d, needNormalization)
+ if (vnode && !Array.isArray(vnode)) {
+ vnode.fnScopeId = options._scopeId
+ vnode.fnContext = parent
+ }
+ return vnode
+ }
+ } else {
+ this._c = (a, b, c, d) => createElement(contextVm, a, b, c, d, needNormalization)
+ }
+}
+
+installRenderHelpers(FunctionalRenderContext.prototype)
+
+export function createFunctionalComponent (
+ Ctor: Class<Component>,
+ propsData: ?Object,
+ data: VNodeData,
+ contextVm: Component,
+ children: ?Array<VNode>
+): VNode | Array<VNode> | void {
+ const options = Ctor.options
+ const props = {}
+ const propOptions = options.props
+ if (isDef(propOptions)) {
+ for (const key in propOptions) {
+ props[key] = validateProp(key, propOptions, propsData || emptyObject)
+ }
+ } else {
+ if (isDef(data.attrs)) mergeProps(props, data.attrs)
+ if (isDef(data.props)) mergeProps(props, data.props)
+ }
+
+ const renderContext = new FunctionalRenderContext(
+ data,
+ props,
+ children,
+ contextVm,
+ Ctor
+ )
+
+ const vnode = options.render.call(null, renderContext._c, renderContext)
+
+ if (vnode instanceof VNode) {
+ return cloneAndMarkFunctionalResult(vnode, data, renderContext.parent, options)
+ } else if (Array.isArray(vnode)) {
+ const vnodes = normalizeChildren(vnode) || []
+ const res = new Array(vnodes.length)
+ for (let i = 0; i < vnodes.length; i++) {
+ res[i] = cloneAndMarkFunctionalResult(vnodes[i], data, renderContext.parent, options)
+ }
+ return res
+ }
+}
+
+function cloneAndMarkFunctionalResult (vnode, data, contextVm, options) {
+ // #7817 clone node before setting fnContext, otherwise if the node is reused
+ // (e.g. it was from a cached normal slot) the fnContext causes named slots
+ // that should not be matched to match.
+ const clone = cloneVNode(vnode)
+ clone.fnContext = contextVm
+ clone.fnOptions = options
+ if (data.slot) {
+ (clone.data || (clone.data = {})).slot = data.slot
+ }
+ return clone
+}
+
+function mergeProps (to, from) {
+ for (const key in from) {
+ to[camelize(key)] = from[key]
+ }
+}
diff --git a/node_modules/vue/src/core/vdom/helpers/extract-props.js b/node_modules/vue/src/core/vdom/helpers/extract-props.js
new file mode 100644
index 00000000..f2a41661
--- /dev/null
+++ b/node_modules/vue/src/core/vdom/helpers/extract-props.js
@@ -0,0 +1,75 @@
+/* @flow */
+
+import {
+ tip,
+ hasOwn,
+ isDef,
+ isUndef,
+ hyphenate,
+ formatComponentName
+} from 'core/util/index'
+
+export function extractPropsFromVNodeData (
+ data: VNodeData,
+ Ctor: Class<Component>,
+ tag?: string
+): ?Object {
+ // we are only extracting raw values here.
+ // validation and default values are handled in the child
+ // component itself.
+ const propOptions = Ctor.options.props
+ if (isUndef(propOptions)) {
+ return
+ }
+ const res = {}
+ const { attrs, props } = data
+ if (isDef(attrs) || isDef(props)) {
+ for (const key in propOptions) {
+ const altKey = hyphenate(key)
+ if (process.env.NODE_ENV !== 'production') {
+ const keyInLowerCase = key.toLowerCase()
+ if (
+ key !== keyInLowerCase &&
+ attrs && hasOwn(attrs, keyInLowerCase)
+ ) {
+ tip(
+ `Prop "${keyInLowerCase}" is passed to component ` +
+ `${formatComponentName(tag || Ctor)}, but the declared prop name is` +
+ ` "${key}". ` +
+ `Note that HTML attributes are case-insensitive and camelCased ` +
+ `props need to use their kebab-case equivalents when using in-DOM ` +
+ `templates. You should probably use "${altKey}" instead of "${key}".`
+ )
+ }
+ }
+ checkProp(res, props, key, altKey, true) ||
+ checkProp(res, attrs, key, altKey, false)
+ }
+ }
+ return res
+}
+
+function checkProp (
+ res: Object,
+ hash: ?Object,
+ key: string,
+ altKey: string,
+ preserve: boolean
+): boolean {
+ if (isDef(hash)) {
+ if (hasOwn(hash, key)) {
+ res[key] = hash[key]
+ if (!preserve) {
+ delete hash[key]
+ }
+ return true
+ } else if (hasOwn(hash, altKey)) {
+ res[key] = hash[altKey]
+ if (!preserve) {
+ delete hash[altKey]
+ }
+ return true
+ }
+ }
+ return false
+}
diff --git a/node_modules/vue/src/core/vdom/helpers/get-first-component-child.js b/node_modules/vue/src/core/vdom/helpers/get-first-component-child.js
new file mode 100644
index 00000000..f8649dd8
--- /dev/null
+++ b/node_modules/vue/src/core/vdom/helpers/get-first-component-child.js
@@ -0,0 +1,15 @@
+/* @flow */
+
+import { isDef } from 'shared/util'
+import { isAsyncPlaceholder } from './is-async-placeholder'
+
+export function getFirstComponentChild (children: ?Array<VNode>): ?VNode {
+ if (Array.isArray(children)) {
+ for (let i = 0; i < children.length; i++) {
+ const c = children[i]
+ if (isDef(c) && (isDef(c.componentOptions) || isAsyncPlaceholder(c))) {
+ return c
+ }
+ }
+ }
+}
diff --git a/node_modules/vue/src/core/vdom/helpers/index.js b/node_modules/vue/src/core/vdom/helpers/index.js
new file mode 100644
index 00000000..320cf4c4
--- /dev/null
+++ b/node_modules/vue/src/core/vdom/helpers/index.js
@@ -0,0 +1,9 @@
+/* @flow */
+
+export * from './merge-hook'
+export * from './extract-props'
+export * from './update-listeners'
+export * from './normalize-children'
+export * from './resolve-async-component'
+export * from './get-first-component-child'
+export * from './is-async-placeholder'
diff --git a/node_modules/vue/src/core/vdom/helpers/is-async-placeholder.js b/node_modules/vue/src/core/vdom/helpers/is-async-placeholder.js
new file mode 100644
index 00000000..6c4a6596
--- /dev/null
+++ b/node_modules/vue/src/core/vdom/helpers/is-async-placeholder.js
@@ -0,0 +1,5 @@
+/* @flow */
+
+export function isAsyncPlaceholder (node: VNode): boolean {
+ return node.isComment && node.asyncFactory
+}
diff --git a/node_modules/vue/src/core/vdom/helpers/merge-hook.js b/node_modules/vue/src/core/vdom/helpers/merge-hook.js
new file mode 100644
index 00000000..0bb96e8b
--- /dev/null
+++ b/node_modules/vue/src/core/vdom/helpers/merge-hook.js
@@ -0,0 +1,38 @@
+/* @flow */
+
+import VNode from '../vnode'
+import { createFnInvoker } from './update-listeners'
+import { remove, isDef, isUndef, isTrue } from 'shared/util'
+
+export function mergeVNodeHook (def: Object, hookKey: string, hook: Function) {
+ if (def instanceof VNode) {
+ def = def.data.hook || (def.data.hook = {})
+ }
+ let invoker
+ const oldHook = def[hookKey]
+
+ function wrappedHook () {
+ hook.apply(this, arguments)
+ // important: remove merged hook to ensure it's called only once
+ // and prevent memory leak
+ remove(invoker.fns, wrappedHook)
+ }
+
+ if (isUndef(oldHook)) {
+ // no existing hook
+ invoker = createFnInvoker([wrappedHook])
+ } else {
+ /* istanbul ignore if */
+ if (isDef(oldHook.fns) && isTrue(oldHook.merged)) {
+ // already a merged invoker
+ invoker = oldHook
+ invoker.fns.push(wrappedHook)
+ } else {
+ // existing plain hook
+ invoker = createFnInvoker([oldHook, wrappedHook])
+ }
+ }
+
+ invoker.merged = true
+ def[hookKey] = invoker
+}
diff --git a/node_modules/vue/src/core/vdom/helpers/normalize-children.js b/node_modules/vue/src/core/vdom/helpers/normalize-children.js
new file mode 100644
index 00000000..a4622ef4
--- /dev/null
+++ b/node_modules/vue/src/core/vdom/helpers/normalize-children.js
@@ -0,0 +1,89 @@
+/* @flow */
+
+import VNode, { createTextVNode } from 'core/vdom/vnode'
+import { isFalse, isTrue, isDef, isUndef, isPrimitive } from 'shared/util'
+
+// The template compiler attempts to minimize the need for normalization by
+// statically analyzing the template at compile time.
+//
+// For plain HTML markup, normalization can be completely skipped because the
+// generated render function is guaranteed to return Array<VNode>. There are
+// two cases where extra normalization is needed:
+
+// 1. When the children contains components - because a functional component
+// may return an Array instead of a single root. In this case, just a simple
+// normalization is needed - if any child is an Array, we flatten the whole
+// thing with Array.prototype.concat. It is guaranteed to be only 1-level deep
+// because functional components already normalize their own children.
+export function simpleNormalizeChildren (children: any) {
+ for (let i = 0; i < children.length; i++) {
+ if (Array.isArray(children[i])) {
+ return Array.prototype.concat.apply([], children)
+ }
+ }
+ return children
+}
+
+// 2. When the children contains constructs that always generated nested Arrays,
+// e.g. <template>, <slot>, v-for, or when the children is provided by user
+// with hand-written render functions / JSX. In such cases a full normalization
+// is needed to cater to all possible types of children values.
+export function normalizeChildren (children: any): ?Array<VNode> {
+ return isPrimitive(children)
+ ? [createTextVNode(children)]
+ : Array.isArray(children)
+ ? normalizeArrayChildren(children)
+ : undefined
+}
+
+function isTextNode (node): boolean {
+ return isDef(node) && isDef(node.text) && isFalse(node.isComment)
+}
+
+function normalizeArrayChildren (children: any, nestedIndex?: string): Array<VNode> {
+ const res = []
+ let i, c, lastIndex, last
+ for (i = 0; i < children.length; i++) {
+ c = children[i]
+ if (isUndef(c) || typeof c === 'boolean') continue
+ lastIndex = res.length - 1
+ last = res[lastIndex]
+ // nested
+ if (Array.isArray(c)) {
+ if (c.length > 0) {
+ c = normalizeArrayChildren(c, `${nestedIndex || ''}_${i}`)
+ // merge adjacent text nodes
+ if (isTextNode(c[0]) && isTextNode(last)) {
+ res[lastIndex] = createTextVNode(last.text + (c[0]: any).text)
+ c.shift()
+ }
+ res.push.apply(res, c)
+ }
+ } else if (isPrimitive(c)) {
+ if (isTextNode(last)) {
+ // merge adjacent text nodes
+ // this is necessary for SSR hydration because text nodes are
+ // essentially merged when rendered to HTML strings
+ res[lastIndex] = createTextVNode(last.text + c)
+ } else if (c !== '') {
+ // convert primitive to vnode
+ res.push(createTextVNode(c))
+ }
+ } else {
+ if (isTextNode(c) && isTextNode(last)) {
+ // merge adjacent text nodes
+ res[lastIndex] = createTextVNode(last.text + c.text)
+ } else {
+ // default key for nested array children (likely generated by v-for)
+ if (isTrue(children._isVList) &&
+ isDef(c.tag) &&
+ isUndef(c.key) &&
+ isDef(nestedIndex)) {
+ c.key = `__vlist${nestedIndex}_${i}__`
+ }
+ res.push(c)
+ }
+ }
+ }
+ return res
+}
diff --git a/node_modules/vue/src/core/vdom/helpers/resolve-async-component.js b/node_modules/vue/src/core/vdom/helpers/resolve-async-component.js
new file mode 100644
index 00000000..99ce5ce4
--- /dev/null
+++ b/node_modules/vue/src/core/vdom/helpers/resolve-async-component.js
@@ -0,0 +1,140 @@
+/* @flow */
+
+import {
+ warn,
+ once,
+ isDef,
+ isUndef,
+ isTrue,
+ isObject,
+ hasSymbol
+} from 'core/util/index'
+
+import { createEmptyVNode } from 'core/vdom/vnode'
+
+function ensureCtor (comp: any, base) {
+ if (
+ comp.__esModule ||
+ (hasSymbol && comp[Symbol.toStringTag] === 'Module')
+ ) {
+ comp = comp.default
+ }
+ return isObject(comp)
+ ? base.extend(comp)
+ : comp
+}
+
+export function createAsyncPlaceholder (
+ factory: Function,
+ data: ?VNodeData,
+ context: Component,
+ children: ?Array<VNode>,
+ tag: ?string
+): VNode {
+ const node = createEmptyVNode()
+ node.asyncFactory = factory
+ node.asyncMeta = { data, context, children, tag }
+ return node
+}
+
+export function resolveAsyncComponent (
+ factory: Function,
+ baseCtor: Class<Component>,
+ context: Component
+): Class<Component> | void {
+ if (isTrue(factory.error) && isDef(factory.errorComp)) {
+ return factory.errorComp
+ }
+
+ if (isDef(factory.resolved)) {
+ return factory.resolved
+ }
+
+ if (isTrue(factory.loading) && isDef(factory.loadingComp)) {
+ return factory.loadingComp
+ }
+
+ if (isDef(factory.contexts)) {
+ // already pending
+ factory.contexts.push(context)
+ } else {
+ const contexts = factory.contexts = [context]
+ let sync = true
+
+ const forceRender = () => {
+ for (let i = 0, l = contexts.length; i < l; i++) {
+ contexts[i].$forceUpdate()
+ }
+ }
+
+ const resolve = once((res: Object | Class<Component>) => {
+ // cache resolved
+ factory.resolved = ensureCtor(res, baseCtor)
+ // invoke callbacks only if this is not a synchronous resolve
+ // (async resolves are shimmed as synchronous during SSR)
+ if (!sync) {
+ forceRender()
+ }
+ })
+
+ const reject = once(reason => {
+ process.env.NODE_ENV !== 'production' && warn(
+ `Failed to resolve async component: ${String(factory)}` +
+ (reason ? `\nReason: ${reason}` : '')
+ )
+ if (isDef(factory.errorComp)) {
+ factory.error = true
+ forceRender()
+ }
+ })
+
+ const res = factory(resolve, reject)
+
+ if (isObject(res)) {
+ if (typeof res.then === 'function') {
+ // () => Promise
+ if (isUndef(factory.resolved)) {
+ res.then(resolve, reject)
+ }
+ } else if (isDef(res.component) && typeof res.component.then === 'function') {
+ res.component.then(resolve, reject)
+
+ if (isDef(res.error)) {
+ factory.errorComp = ensureCtor(res.error, baseCtor)
+ }
+
+ if (isDef(res.loading)) {
+ factory.loadingComp = ensureCtor(res.loading, baseCtor)
+ if (res.delay === 0) {
+ factory.loading = true
+ } else {
+ setTimeout(() => {
+ if (isUndef(factory.resolved) && isUndef(factory.error)) {
+ factory.loading = true
+ forceRender()
+ }
+ }, res.delay || 200)
+ }
+ }
+
+ if (isDef(res.timeout)) {
+ setTimeout(() => {
+ if (isUndef(factory.resolved)) {
+ reject(
+ process.env.NODE_ENV !== 'production'
+ ? `timeout (${res.timeout}ms)`
+ : null
+ )
+ }
+ }, res.timeout)
+ }
+ }
+ }
+
+ sync = false
+ // return in case resolved synchronously
+ return factory.loading
+ ? factory.loadingComp
+ : factory.resolved
+ }
+}
diff --git a/node_modules/vue/src/core/vdom/helpers/update-listeners.js b/node_modules/vue/src/core/vdom/helpers/update-listeners.js
new file mode 100644
index 00000000..11c5a2cd
--- /dev/null
+++ b/node_modules/vue/src/core/vdom/helpers/update-listeners.js
@@ -0,0 +1,83 @@
+/* @flow */
+
+import { warn } from 'core/util/index'
+import { cached, isUndef, isPlainObject } from 'shared/util'
+
+const normalizeEvent = cached((name: string): {
+ name: string,
+ once: boolean,
+ capture: boolean,
+ passive: boolean,
+ handler?: Function,
+ params?: Array<any>
+} => {
+ const passive = name.charAt(0) === '&'
+ name = passive ? name.slice(1) : name
+ const once = name.charAt(0) === '~' // Prefixed last, checked first
+ name = once ? name.slice(1) : name
+ const capture = name.charAt(0) === '!'
+ name = capture ? name.slice(1) : name
+ return {
+ name,
+ once,
+ capture,
+ passive
+ }
+})
+
+export function createFnInvoker (fns: Function | Array<Function>): Function {
+ function invoker () {
+ const fns = invoker.fns
+ if (Array.isArray(fns)) {
+ const cloned = fns.slice()
+ for (let i = 0; i < cloned.length; i++) {
+ cloned[i].apply(null, arguments)
+ }
+ } else {
+ // return handler return value for single handlers
+ return fns.apply(null, arguments)
+ }
+ }
+ invoker.fns = fns
+ return invoker
+}
+
+export function updateListeners (
+ on: Object,
+ oldOn: Object,
+ add: Function,
+ remove: Function,
+ vm: Component
+) {
+ let name, def, cur, old, event
+ for (name in on) {
+ def = cur = on[name]
+ old = oldOn[name]
+ event = normalizeEvent(name)
+ /* istanbul ignore if */
+ if (__WEEX__ && isPlainObject(def)) {
+ cur = def.handler
+ event.params = def.params
+ }
+ if (isUndef(cur)) {
+ process.env.NODE_ENV !== 'production' && warn(
+ `Invalid handler for event "${event.name}": got ` + String(cur),
+ vm
+ )
+ } else if (isUndef(old)) {
+ if (isUndef(cur.fns)) {
+ cur = on[name] = createFnInvoker(cur)
+ }
+ add(event.name, cur, event.once, event.capture, event.passive, event.params)
+ } else if (cur !== old) {
+ old.fns = cur
+ on[name] = old
+ }
+ }
+ for (name in oldOn) {
+ if (isUndef(on[name])) {
+ event = normalizeEvent(name)
+ remove(event.name, oldOn[name], event.capture)
+ }
+ }
+}
diff --git a/node_modules/vue/src/core/vdom/modules/directives.js b/node_modules/vue/src/core/vdom/modules/directives.js
new file mode 100644
index 00000000..639982fa
--- /dev/null
+++ b/node_modules/vue/src/core/vdom/modules/directives.js
@@ -0,0 +1,119 @@
+/* @flow */
+
+import { emptyNode } from 'core/vdom/patch'
+import { resolveAsset, handleError } from 'core/util/index'
+import { mergeVNodeHook } from 'core/vdom/helpers/index'
+
+export default {
+ create: updateDirectives,
+ update: updateDirectives,
+ destroy: function unbindDirectives (vnode: VNodeWithData) {
+ updateDirectives(vnode, emptyNode)
+ }
+}
+
+function updateDirectives (oldVnode: VNodeWithData, vnode: VNodeWithData) {
+ if (oldVnode.data.directives || vnode.data.directives) {
+ _update(oldVnode, vnode)
+ }
+}
+
+function _update (oldVnode, vnode) {
+ const isCreate = oldVnode === emptyNode
+ const isDestroy = vnode === emptyNode
+ const oldDirs = normalizeDirectives(oldVnode.data.directives, oldVnode.context)
+ const newDirs = normalizeDirectives(vnode.data.directives, vnode.context)
+
+ const dirsWithInsert = []
+ const dirsWithPostpatch = []
+
+ let key, oldDir, dir
+ for (key in newDirs) {
+ oldDir = oldDirs[key]
+ dir = newDirs[key]
+ if (!oldDir) {
+ // new directive, bind
+ callHook(dir, 'bind', vnode, oldVnode)
+ if (dir.def && dir.def.inserted) {
+ dirsWithInsert.push(dir)
+ }
+ } else {
+ // existing directive, update
+ dir.oldValue = oldDir.value
+ callHook(dir, 'update', vnode, oldVnode)
+ if (dir.def && dir.def.componentUpdated) {
+ dirsWithPostpatch.push(dir)
+ }
+ }
+ }
+
+ if (dirsWithInsert.length) {
+ const callInsert = () => {
+ for (let i = 0; i < dirsWithInsert.length; i++) {
+ callHook(dirsWithInsert[i], 'inserted', vnode, oldVnode)
+ }
+ }
+ if (isCreate) {
+ mergeVNodeHook(vnode, 'insert', callInsert)
+ } else {
+ callInsert()
+ }
+ }
+
+ if (dirsWithPostpatch.length) {
+ mergeVNodeHook(vnode, 'postpatch', () => {
+ for (let i = 0; i < dirsWithPostpatch.length; i++) {
+ callHook(dirsWithPostpatch[i], 'componentUpdated', vnode, oldVnode)
+ }
+ })
+ }
+
+ if (!isCreate) {
+ for (key in oldDirs) {
+ if (!newDirs[key]) {
+ // no longer present, unbind
+ callHook(oldDirs[key], 'unbind', oldVnode, oldVnode, isDestroy)
+ }
+ }
+ }
+}
+
+const emptyModifiers = Object.create(null)
+
+function normalizeDirectives (
+ dirs: ?Array<VNodeDirective>,
+ vm: Component
+): { [key: string]: VNodeDirective } {
+ const res = Object.create(null)
+ if (!dirs) {
+ // $flow-disable-line
+ return res
+ }
+ let i, dir
+ for (i = 0; i < dirs.length; i++) {
+ dir = dirs[i]
+ if (!dir.modifiers) {
+ // $flow-disable-line
+ dir.modifiers = emptyModifiers
+ }
+ res[getRawDirName(dir)] = dir
+ dir.def = resolveAsset(vm.$options, 'directives', dir.name, true)
+ }
+ // $flow-disable-line
+ return res
+}
+
+function getRawDirName (dir: VNodeDirective): string {
+ return dir.rawName || `${dir.name}.${Object.keys(dir.modifiers || {}).join('.')}`
+}
+
+function callHook (dir, hook, vnode, oldVnode, isDestroy) {
+ const fn = dir.def && dir.def[hook]
+ if (fn) {
+ try {
+ fn(vnode.elm, dir, vnode, oldVnode, isDestroy)
+ } catch (e) {
+ handleError(e, vnode.context, `directive ${dir.name} ${hook} hook`)
+ }
+ }
+}
diff --git a/node_modules/vue/src/core/vdom/modules/index.js b/node_modules/vue/src/core/vdom/modules/index.js
new file mode 100644
index 00000000..727c8646
--- /dev/null
+++ b/node_modules/vue/src/core/vdom/modules/index.js
@@ -0,0 +1,7 @@
+import directives from './directives'
+import ref from './ref'
+
+export default [
+ ref,
+ directives
+]
diff --git a/node_modules/vue/src/core/vdom/modules/ref.js b/node_modules/vue/src/core/vdom/modules/ref.js
new file mode 100644
index 00000000..aa9bdcfc
--- /dev/null
+++ b/node_modules/vue/src/core/vdom/modules/ref.js
@@ -0,0 +1,45 @@
+/* @flow */
+
+import { remove, isDef } from 'shared/util'
+
+export default {
+ create (_: any, vnode: VNodeWithData) {
+ registerRef(vnode)
+ },
+ update (oldVnode: VNodeWithData, vnode: VNodeWithData) {
+ if (oldVnode.data.ref !== vnode.data.ref) {
+ registerRef(oldVnode, true)
+ registerRef(vnode)
+ }
+ },
+ destroy (vnode: VNodeWithData) {
+ registerRef(vnode, true)
+ }
+}
+
+export function registerRef (vnode: VNodeWithData, isRemoval: ?boolean) {
+ const key = vnode.data.ref
+ if (!isDef(key)) return
+
+ const vm = vnode.context
+ const ref = vnode.componentInstance || vnode.elm
+ const refs = vm.$refs
+ if (isRemoval) {
+ if (Array.isArray(refs[key])) {
+ remove(refs[key], ref)
+ } else if (refs[key] === ref) {
+ refs[key] = undefined
+ }
+ } else {
+ if (vnode.data.refInFor) {
+ if (!Array.isArray(refs[key])) {
+ refs[key] = [ref]
+ } else if (refs[key].indexOf(ref) < 0) {
+ // $flow-disable-line
+ refs[key].push(ref)
+ }
+ } else {
+ refs[key] = ref
+ }
+ }
+}
diff --git a/node_modules/vue/src/core/vdom/patch.js b/node_modules/vue/src/core/vdom/patch.js
new file mode 100644
index 00000000..9f3bcc65
--- /dev/null
+++ b/node_modules/vue/src/core/vdom/patch.js
@@ -0,0 +1,787 @@
+/**
+ * Virtual DOM patching algorithm based on Snabbdom by
+ * Simon Friis Vindum (@paldepind)
+ * Licensed under the MIT License
+ * https://github.com/paldepind/snabbdom/blob/master/LICENSE
+ *
+ * modified by Evan You (@yyx990803)
+ *
+ * Not type-checking this because this file is perf-critical and the cost
+ * of making flow understand it is not worth it.
+ */
+
+import VNode, { cloneVNode } from './vnode'
+import config from '../config'
+import { SSR_ATTR } from 'shared/constants'
+import { registerRef } from './modules/ref'
+import { traverse } from '../observer/traverse'
+import { activeInstance } from '../instance/lifecycle'
+import { isTextInputType } from 'web/util/element'
+
+import {
+ warn,
+ isDef,
+ isUndef,
+ isTrue,
+ makeMap,
+ isRegExp,
+ isPrimitive
+} from '../util/index'
+
+export const emptyNode = new VNode('', {}, [])
+
+const hooks = ['create', 'activate', 'update', 'remove', 'destroy']
+
+function sameVnode (a, b) {
+ return (
+ a.key === b.key && (
+ (
+ a.tag === b.tag &&
+ a.isComment === b.isComment &&
+ isDef(a.data) === isDef(b.data) &&
+ sameInputType(a, b)
+ ) || (
+ isTrue(a.isAsyncPlaceholder) &&
+ a.asyncFactory === b.asyncFactory &&
+ isUndef(b.asyncFactory.error)
+ )
+ )
+ )
+}
+
+function sameInputType (a, b) {
+ if (a.tag !== 'input') return true
+ let i
+ const typeA = isDef(i = a.data) && isDef(i = i.attrs) && i.type
+ const typeB = isDef(i = b.data) && isDef(i = i.attrs) && i.type
+ return typeA === typeB || isTextInputType(typeA) && isTextInputType(typeB)
+}
+
+function createKeyToOldIdx (children, beginIdx, endIdx) {
+ let i, key
+ const map = {}
+ for (i = beginIdx; i <= endIdx; ++i) {
+ key = children[i].key
+ if (isDef(key)) map[key] = i
+ }
+ return map
+}
+
+export function createPatchFunction (backend) {
+ let i, j
+ const cbs = {}
+
+ const { modules, nodeOps } = backend
+
+ for (i = 0; i < hooks.length; ++i) {
+ cbs[hooks[i]] = []
+ for (j = 0; j < modules.length; ++j) {
+ if (isDef(modules[j][hooks[i]])) {
+ cbs[hooks[i]].push(modules[j][hooks[i]])
+ }
+ }
+ }
+
+ function emptyNodeAt (elm) {
+ return new VNode(nodeOps.tagName(elm).toLowerCase(), {}, [], undefined, elm)
+ }
+
+ function createRmCb (childElm, listeners) {
+ function remove () {
+ if (--remove.listeners === 0) {
+ removeNode(childElm)
+ }
+ }
+ remove.listeners = listeners
+ return remove
+ }
+
+ function removeNode (el) {
+ const parent = nodeOps.parentNode(el)
+ // element may have already been removed due to v-html / v-text
+ if (isDef(parent)) {
+ nodeOps.removeChild(parent, el)
+ }
+ }
+
+ function isUnknownElement (vnode, inVPre) {
+ return (
+ !inVPre &&
+ !vnode.ns &&
+ !(
+ config.ignoredElements.length &&
+ config.ignoredElements.some(ignore => {
+ return isRegExp(ignore)
+ ? ignore.test(vnode.tag)
+ : ignore === vnode.tag
+ })
+ ) &&
+ config.isUnknownElement(vnode.tag)
+ )
+ }
+
+ let creatingElmInVPre = 0
+
+ function createElm (
+ vnode,
+ insertedVnodeQueue,
+ parentElm,
+ refElm,
+ nested,
+ ownerArray,
+ index
+ ) {
+ if (isDef(vnode.elm) && isDef(ownerArray)) {
+ // This vnode was used in a previous render!
+ // now it's used as a new node, overwriting its elm would cause
+ // potential patch errors down the road when it's used as an insertion
+ // reference node. Instead, we clone the node on-demand before creating
+ // associated DOM element for it.
+ vnode = ownerArray[index] = cloneVNode(vnode)
+ }
+
+ vnode.isRootInsert = !nested // for transition enter check
+ if (createComponent(vnode, insertedVnodeQueue, parentElm, refElm)) {
+ return
+ }
+
+ const data = vnode.data
+ const children = vnode.children
+ const tag = vnode.tag
+ if (isDef(tag)) {
+ if (process.env.NODE_ENV !== 'production') {
+ if (data && data.pre) {
+ creatingElmInVPre++
+ }
+ if (isUnknownElement(vnode, creatingElmInVPre)) {
+ warn(
+ 'Unknown custom element: <' + tag + '> - did you ' +
+ 'register the component correctly? For recursive components, ' +
+ 'make sure to provide the "name" option.',
+ vnode.context
+ )
+ }
+ }
+
+ vnode.elm = vnode.ns
+ ? nodeOps.createElementNS(vnode.ns, tag)
+ : nodeOps.createElement(tag, vnode)
+ setScope(vnode)
+
+ /* istanbul ignore if */
+ if (__WEEX__) {
+ // in Weex, the default insertion order is parent-first.
+ // List items can be optimized to use children-first insertion
+ // with append="tree".
+ const appendAsTree = isDef(data) && isTrue(data.appendAsTree)
+ if (!appendAsTree) {
+ if (isDef(data)) {
+ invokeCreateHooks(vnode, insertedVnodeQueue)
+ }
+ insert(parentElm, vnode.elm, refElm)
+ }
+ createChildren(vnode, children, insertedVnodeQueue)
+ if (appendAsTree) {
+ if (isDef(data)) {
+ invokeCreateHooks(vnode, insertedVnodeQueue)
+ }
+ insert(parentElm, vnode.elm, refElm)
+ }
+ } else {
+ createChildren(vnode, children, insertedVnodeQueue)
+ if (isDef(data)) {
+ invokeCreateHooks(vnode, insertedVnodeQueue)
+ }
+ insert(parentElm, vnode.elm, refElm)
+ }
+
+ if (process.env.NODE_ENV !== 'production' && data && data.pre) {
+ creatingElmInVPre--
+ }
+ } else if (isTrue(vnode.isComment)) {
+ vnode.elm = nodeOps.createComment(vnode.text)
+ insert(parentElm, vnode.elm, refElm)
+ } else {
+ vnode.elm = nodeOps.createTextNode(vnode.text)
+ insert(parentElm, vnode.elm, refElm)
+ }
+ }
+
+ function createComponent (vnode, insertedVnodeQueue, parentElm, refElm) {
+ let i = vnode.data
+ if (isDef(i)) {
+ const isReactivated = isDef(vnode.componentInstance) && i.keepAlive
+ if (isDef(i = i.hook) && isDef(i = i.init)) {
+ i(vnode, false /* hydrating */, parentElm, refElm)
+ }
+ // after calling the init hook, if the vnode is a child component
+ // it should've created a child instance and mounted it. the child
+ // component also has set the placeholder vnode's elm.
+ // in that case we can just return the element and be done.
+ if (isDef(vnode.componentInstance)) {
+ initComponent(vnode, insertedVnodeQueue)
+ if (isTrue(isReactivated)) {
+ reactivateComponent(vnode, insertedVnodeQueue, parentElm, refElm)
+ }
+ return true
+ }
+ }
+ }
+
+ function initComponent (vnode, insertedVnodeQueue) {
+ if (isDef(vnode.data.pendingInsert)) {
+ insertedVnodeQueue.push.apply(insertedVnodeQueue, vnode.data.pendingInsert)
+ vnode.data.pendingInsert = null
+ }
+ vnode.elm = vnode.componentInstance.$el
+ if (isPatchable(vnode)) {
+ invokeCreateHooks(vnode, insertedVnodeQueue)
+ setScope(vnode)
+ } else {
+ // empty component root.
+ // skip all element-related modules except for ref (#3455)
+ registerRef(vnode)
+ // make sure to invoke the insert hook
+ insertedVnodeQueue.push(vnode)
+ }
+ }
+
+ function reactivateComponent (vnode, insertedVnodeQueue, parentElm, refElm) {
+ let i
+ // hack for #4339: a reactivated component with inner transition
+ // does not trigger because the inner node's created hooks are not called
+ // again. It's not ideal to involve module-specific logic in here but
+ // there doesn't seem to be a better way to do it.
+ let innerNode = vnode
+ while (innerNode.componentInstance) {
+ innerNode = innerNode.componentInstance._vnode
+ if (isDef(i = innerNode.data) && isDef(i = i.transition)) {
+ for (i = 0; i < cbs.activate.length; ++i) {
+ cbs.activate[i](emptyNode, innerNode)
+ }
+ insertedVnodeQueue.push(innerNode)
+ break
+ }
+ }
+ // unlike a newly created component,
+ // a reactivated keep-alive component doesn't insert itself
+ insert(parentElm, vnode.elm, refElm)
+ }
+
+ function insert (parent, elm, ref) {
+ if (isDef(parent)) {
+ if (isDef(ref)) {
+ if (ref.parentNode === parent) {
+ nodeOps.insertBefore(parent, elm, ref)
+ }
+ } else {
+ nodeOps.appendChild(parent, elm)
+ }
+ }
+ }
+
+ function createChildren (vnode, children, insertedVnodeQueue) {
+ if (Array.isArray(children)) {
+ if (process.env.NODE_ENV !== 'production') {
+ checkDuplicateKeys(children)
+ }
+ for (let i = 0; i < children.length; ++i) {
+ createElm(children[i], insertedVnodeQueue, vnode.elm, null, true, children, i)
+ }
+ } else if (isPrimitive(vnode.text)) {
+ nodeOps.appendChild(vnode.elm, nodeOps.createTextNode(String(vnode.text)))
+ }
+ }
+
+ function isPatchable (vnode) {
+ while (vnode.componentInstance) {
+ vnode = vnode.componentInstance._vnode
+ }
+ return isDef(vnode.tag)
+ }
+
+ function invokeCreateHooks (vnode, insertedVnodeQueue) {
+ for (let i = 0; i < cbs.create.length; ++i) {
+ cbs.create[i](emptyNode, vnode)
+ }
+ i = vnode.data.hook // Reuse variable
+ if (isDef(i)) {
+ if (isDef(i.create)) i.create(emptyNode, vnode)
+ if (isDef(i.insert)) insertedVnodeQueue.push(vnode)
+ }
+ }
+
+ // set scope id attribute for scoped CSS.
+ // this is implemented as a special case to avoid the overhead
+ // of going through the normal attribute patching process.
+ function setScope (vnode) {
+ let i
+ if (isDef(i = vnode.fnScopeId)) {
+ nodeOps.setStyleScope(vnode.elm, i)
+ } else {
+ let ancestor = vnode
+ while (ancestor) {
+ if (isDef(i = ancestor.context) && isDef(i = i.$options._scopeId)) {
+ nodeOps.setStyleScope(vnode.elm, i)
+ }
+ ancestor = ancestor.parent
+ }
+ }
+ // for slot content they should also get the scopeId from the host instance.
+ if (isDef(i = activeInstance) &&
+ i !== vnode.context &&
+ i !== vnode.fnContext &&
+ isDef(i = i.$options._scopeId)
+ ) {
+ nodeOps.setStyleScope(vnode.elm, i)
+ }
+ }
+
+ function addVnodes (parentElm, refElm, vnodes, startIdx, endIdx, insertedVnodeQueue) {
+ for (; startIdx <= endIdx; ++startIdx) {
+ createElm(vnodes[startIdx], insertedVnodeQueue, parentElm, refElm, false, vnodes, startIdx)
+ }
+ }
+
+ function invokeDestroyHook (vnode) {
+ let i, j
+ const data = vnode.data
+ if (isDef(data)) {
+ if (isDef(i = data.hook) && isDef(i = i.destroy)) i(vnode)
+ for (i = 0; i < cbs.destroy.length; ++i) cbs.destroy[i](vnode)
+ }
+ if (isDef(i = vnode.children)) {
+ for (j = 0; j < vnode.children.length; ++j) {
+ invokeDestroyHook(vnode.children[j])
+ }
+ }
+ }
+
+ function removeVnodes (parentElm, vnodes, startIdx, endIdx) {
+ for (; startIdx <= endIdx; ++startIdx) {
+ const ch = vnodes[startIdx]
+ if (isDef(ch)) {
+ if (isDef(ch.tag)) {
+ removeAndInvokeRemoveHook(ch)
+ invokeDestroyHook(ch)
+ } else { // Text node
+ removeNode(ch.elm)
+ }
+ }
+ }
+ }
+
+ function removeAndInvokeRemoveHook (vnode, rm) {
+ if (isDef(rm) || isDef(vnode.data)) {
+ let i
+ const listeners = cbs.remove.length + 1
+ if (isDef(rm)) {
+ // we have a recursively passed down rm callback
+ // increase the listeners count
+ rm.listeners += listeners
+ } else {
+ // directly removing
+ rm = createRmCb(vnode.elm, listeners)
+ }
+ // recursively invoke hooks on child component root node
+ if (isDef(i = vnode.componentInstance) && isDef(i = i._vnode) && isDef(i.data)) {
+ removeAndInvokeRemoveHook(i, rm)
+ }
+ for (i = 0; i < cbs.remove.length; ++i) {
+ cbs.remove[i](vnode, rm)
+ }
+ if (isDef(i = vnode.data.hook) && isDef(i = i.remove)) {
+ i(vnode, rm)
+ } else {
+ rm()
+ }
+ } else {
+ removeNode(vnode.elm)
+ }
+ }
+
+ function updateChildren (parentElm, oldCh, newCh, insertedVnodeQueue, removeOnly) {
+ let oldStartIdx = 0
+ let newStartIdx = 0
+ let oldEndIdx = oldCh.length - 1
+ let oldStartVnode = oldCh[0]
+ let oldEndVnode = oldCh[oldEndIdx]
+ let newEndIdx = newCh.length - 1
+ let newStartVnode = newCh[0]
+ let newEndVnode = newCh[newEndIdx]
+ let oldKeyToIdx, idxInOld, vnodeToMove, refElm
+
+ // removeOnly is a special flag used only by <transition-group>
+ // to ensure removed elements stay in correct relative positions
+ // during leaving transitions
+ const canMove = !removeOnly
+
+ if (process.env.NODE_ENV !== 'production') {
+ checkDuplicateKeys(newCh)
+ }
+
+ while (oldStartIdx <= oldEndIdx && newStartIdx <= newEndIdx) {
+ if (isUndef(oldStartVnode)) {
+ oldStartVnode = oldCh[++oldStartIdx] // Vnode has been moved left
+ } else if (isUndef(oldEndVnode)) {
+ oldEndVnode = oldCh[--oldEndIdx]
+ } else if (sameVnode(oldStartVnode, newStartVnode)) {
+ patchVnode(oldStartVnode, newStartVnode, insertedVnodeQueue)
+ oldStartVnode = oldCh[++oldStartIdx]
+ newStartVnode = newCh[++newStartIdx]
+ } else if (sameVnode(oldEndVnode, newEndVnode)) {
+ patchVnode(oldEndVnode, newEndVnode, insertedVnodeQueue)
+ oldEndVnode = oldCh[--oldEndIdx]
+ newEndVnode = newCh[--newEndIdx]
+ } else if (sameVnode(oldStartVnode, newEndVnode)) { // Vnode moved right
+ patchVnode(oldStartVnode, newEndVnode, insertedVnodeQueue)
+ canMove && nodeOps.insertBefore(parentElm, oldStartVnode.elm, nodeOps.nextSibling(oldEndVnode.elm))
+ oldStartVnode = oldCh[++oldStartIdx]
+ newEndVnode = newCh[--newEndIdx]
+ } else if (sameVnode(oldEndVnode, newStartVnode)) { // Vnode moved left
+ patchVnode(oldEndVnode, newStartVnode, insertedVnodeQueue)
+ canMove && nodeOps.insertBefore(parentElm, oldEndVnode.elm, oldStartVnode.elm)
+ oldEndVnode = oldCh[--oldEndIdx]
+ newStartVnode = newCh[++newStartIdx]
+ } else {
+ if (isUndef(oldKeyToIdx)) oldKeyToIdx = createKeyToOldIdx(oldCh, oldStartIdx, oldEndIdx)
+ idxInOld = isDef(newStartVnode.key)
+ ? oldKeyToIdx[newStartVnode.key]
+ : findIdxInOld(newStartVnode, oldCh, oldStartIdx, oldEndIdx)
+ if (isUndef(idxInOld)) { // New element
+ createElm(newStartVnode, insertedVnodeQueue, parentElm, oldStartVnode.elm, false, newCh, newStartIdx)
+ } else {
+ vnodeToMove = oldCh[idxInOld]
+ if (sameVnode(vnodeToMove, newStartVnode)) {
+ patchVnode(vnodeToMove, newStartVnode, insertedVnodeQueue)
+ oldCh[idxInOld] = undefined
+ canMove && nodeOps.insertBefore(parentElm, vnodeToMove.elm, oldStartVnode.elm)
+ } else {
+ // same key but different element. treat as new element
+ createElm(newStartVnode, insertedVnodeQueue, parentElm, oldStartVnode.elm, false, newCh, newStartIdx)
+ }
+ }
+ newStartVnode = newCh[++newStartIdx]
+ }
+ }
+ if (oldStartIdx > oldEndIdx) {
+ refElm = isUndef(newCh[newEndIdx + 1]) ? null : newCh[newEndIdx + 1].elm
+ addVnodes(parentElm, refElm, newCh, newStartIdx, newEndIdx, insertedVnodeQueue)
+ } else if (newStartIdx > newEndIdx) {
+ removeVnodes(parentElm, oldCh, oldStartIdx, oldEndIdx)
+ }
+ }
+
+ function checkDuplicateKeys (children) {
+ const seenKeys = {}
+ for (let i = 0; i < children.length; i++) {
+ const vnode = children[i]
+ const key = vnode.key
+ if (isDef(key)) {
+ if (seenKeys[key]) {
+ warn(
+ `Duplicate keys detected: '${key}'. This may cause an update error.`,
+ vnode.context
+ )
+ } else {
+ seenKeys[key] = true
+ }
+ }
+ }
+ }
+
+ function findIdxInOld (node, oldCh, start, end) {
+ for (let i = start; i < end; i++) {
+ const c = oldCh[i]
+ if (isDef(c) && sameVnode(node, c)) return i
+ }
+ }
+
+ function patchVnode (oldVnode, vnode, insertedVnodeQueue, removeOnly) {
+ if (oldVnode === vnode) {
+ return
+ }
+
+ const elm = vnode.elm = oldVnode.elm
+
+ if (isTrue(oldVnode.isAsyncPlaceholder)) {
+ if (isDef(vnode.asyncFactory.resolved)) {
+ hydrate(oldVnode.elm, vnode, insertedVnodeQueue)
+ } else {
+ vnode.isAsyncPlaceholder = true
+ }
+ return
+ }
+
+ // reuse element for static trees.
+ // note we only do this if the vnode is cloned -
+ // if the new node is not cloned it means the render functions have been
+ // reset by the hot-reload-api and we need to do a proper re-render.
+ if (isTrue(vnode.isStatic) &&
+ isTrue(oldVnode.isStatic) &&
+ vnode.key === oldVnode.key &&
+ (isTrue(vnode.isCloned) || isTrue(vnode.isOnce))
+ ) {
+ vnode.componentInstance = oldVnode.componentInstance
+ return
+ }
+
+ let i
+ const data = vnode.data
+ if (isDef(data) && isDef(i = data.hook) && isDef(i = i.prepatch)) {
+ i(oldVnode, vnode)
+ }
+
+ const oldCh = oldVnode.children
+ const ch = vnode.children
+ if (isDef(data) && isPatchable(vnode)) {
+ for (i = 0; i < cbs.update.length; ++i) cbs.update[i](oldVnode, vnode)
+ if (isDef(i = data.hook) && isDef(i = i.update)) i(oldVnode, vnode)
+ }
+ if (isUndef(vnode.text)) {
+ if (isDef(oldCh) && isDef(ch)) {
+ if (oldCh !== ch) updateChildren(elm, oldCh, ch, insertedVnodeQueue, removeOnly)
+ } else if (isDef(ch)) {
+ if (isDef(oldVnode.text)) nodeOps.setTextContent(elm, '')
+ addVnodes(elm, null, ch, 0, ch.length - 1, insertedVnodeQueue)
+ } else if (isDef(oldCh)) {
+ removeVnodes(elm, oldCh, 0, oldCh.length - 1)
+ } else if (isDef(oldVnode.text)) {
+ nodeOps.setTextContent(elm, '')
+ }
+ } else if (oldVnode.text !== vnode.text) {
+ nodeOps.setTextContent(elm, vnode.text)
+ }
+ if (isDef(data)) {
+ if (isDef(i = data.hook) && isDef(i = i.postpatch)) i(oldVnode, vnode)
+ }
+ }
+
+ function invokeInsertHook (vnode, queue, initial) {
+ // delay insert hooks for component root nodes, invoke them after the
+ // element is really inserted
+ if (isTrue(initial) && isDef(vnode.parent)) {
+ vnode.parent.data.pendingInsert = queue
+ } else {
+ for (let i = 0; i < queue.length; ++i) {
+ queue[i].data.hook.insert(queue[i])
+ }
+ }
+ }
+
+ let hydrationBailed = false
+ // list of modules that can skip create hook during hydration because they
+ // are already rendered on the client or has no need for initialization
+ // Note: style is excluded because it relies on initial clone for future
+ // deep updates (#7063).
+ const isRenderedModule = makeMap('attrs,class,staticClass,staticStyle,key')
+
+ // Note: this is a browser-only function so we can assume elms are DOM nodes.
+ function hydrate (elm, vnode, insertedVnodeQueue, inVPre) {
+ let i
+ const { tag, data, children } = vnode
+ inVPre = inVPre || (data && data.pre)
+ vnode.elm = elm
+
+ if (isTrue(vnode.isComment) && isDef(vnode.asyncFactory)) {
+ vnode.isAsyncPlaceholder = true
+ return true
+ }
+ // assert node match
+ if (process.env.NODE_ENV !== 'production') {
+ if (!assertNodeMatch(elm, vnode, inVPre)) {
+ return false
+ }
+ }
+ if (isDef(data)) {
+ if (isDef(i = data.hook) && isDef(i = i.init)) i(vnode, true /* hydrating */)
+ if (isDef(i = vnode.componentInstance)) {
+ // child component. it should have hydrated its own tree.
+ initComponent(vnode, insertedVnodeQueue)
+ return true
+ }
+ }
+ if (isDef(tag)) {
+ if (isDef(children)) {
+ // empty element, allow client to pick up and populate children
+ if (!elm.hasChildNodes()) {
+ createChildren(vnode, children, insertedVnodeQueue)
+ } else {
+ // v-html and domProps: innerHTML
+ if (isDef(i = data) && isDef(i = i.domProps) && isDef(i = i.innerHTML)) {
+ if (i !== elm.innerHTML) {
+ /* istanbul ignore if */
+ if (process.env.NODE_ENV !== 'production' &&
+ typeof console !== 'undefined' &&
+ !hydrationBailed
+ ) {
+ hydrationBailed = true
+ console.warn('Parent: ', elm)
+ console.warn('server innerHTML: ', i)
+ console.warn('client innerHTML: ', elm.innerHTML)
+ }
+ return false
+ }
+ } else {
+ // iterate and compare children lists
+ let childrenMatch = true
+ let childNode = elm.firstChild
+ for (let i = 0; i < children.length; i++) {
+ if (!childNode || !hydrate(childNode, children[i], insertedVnodeQueue, inVPre)) {
+ childrenMatch = false
+ break
+ }
+ childNode = childNode.nextSibling
+ }
+ // if childNode is not null, it means the actual childNodes list is
+ // longer than the virtual children list.
+ if (!childrenMatch || childNode) {
+ /* istanbul ignore if */
+ if (process.env.NODE_ENV !== 'production' &&
+ typeof console !== 'undefined' &&
+ !hydrationBailed
+ ) {
+ hydrationBailed = true
+ console.warn('Parent: ', elm)
+ console.warn('Mismatching childNodes vs. VNodes: ', elm.childNodes, children)
+ }
+ return false
+ }
+ }
+ }
+ }
+ if (isDef(data)) {
+ let fullInvoke = false
+ for (const key in data) {
+ if (!isRenderedModule(key)) {
+ fullInvoke = true
+ invokeCreateHooks(vnode, insertedVnodeQueue)
+ break
+ }
+ }
+ if (!fullInvoke && data['class']) {
+ // ensure collecting deps for deep class bindings for future updates
+ traverse(data['class'])
+ }
+ }
+ } else if (elm.data !== vnode.text) {
+ elm.data = vnode.text
+ }
+ return true
+ }
+
+ function assertNodeMatch (node, vnode, inVPre) {
+ if (isDef(vnode.tag)) {
+ return vnode.tag.indexOf('vue-component') === 0 || (
+ !isUnknownElement(vnode, inVPre) &&
+ vnode.tag.toLowerCase() === (node.tagName && node.tagName.toLowerCase())
+ )
+ } else {
+ return node.nodeType === (vnode.isComment ? 8 : 3)
+ }
+ }
+
+ return function patch (oldVnode, vnode, hydrating, removeOnly, parentElm, refElm) {
+ if (isUndef(vnode)) {
+ if (isDef(oldVnode)) invokeDestroyHook(oldVnode)
+ return
+ }
+
+ let isInitialPatch = false
+ const insertedVnodeQueue = []
+
+ if (isUndef(oldVnode)) {
+ // empty mount (likely as component), create new root element
+ isInitialPatch = true
+ createElm(vnode, insertedVnodeQueue, parentElm, refElm)
+ } else {
+ const isRealElement = isDef(oldVnode.nodeType)
+ if (!isRealElement && sameVnode(oldVnode, vnode)) {
+ // patch existing root node
+ patchVnode(oldVnode, vnode, insertedVnodeQueue, removeOnly)
+ } else {
+ if (isRealElement) {
+ // mounting to a real element
+ // check if this is server-rendered content and if we can perform
+ // a successful hydration.
+ if (oldVnode.nodeType === 1 && oldVnode.hasAttribute(SSR_ATTR)) {
+ oldVnode.removeAttribute(SSR_ATTR)
+ hydrating = true
+ }
+ if (isTrue(hydrating)) {
+ if (hydrate(oldVnode, vnode, insertedVnodeQueue)) {
+ invokeInsertHook(vnode, insertedVnodeQueue, true)
+ return oldVnode
+ } else if (process.env.NODE_ENV !== 'production') {
+ warn(
+ 'The client-side rendered virtual DOM tree is not matching ' +
+ 'server-rendered content. This is likely caused by incorrect ' +
+ 'HTML markup, for example nesting block-level elements inside ' +
+ '<p>, or missing <tbody>. Bailing hydration and performing ' +
+ 'full client-side render.'
+ )
+ }
+ }
+ // either not server-rendered, or hydration failed.
+ // create an empty node and replace it
+ oldVnode = emptyNodeAt(oldVnode)
+ }
+
+ // replacing existing element
+ const oldElm = oldVnode.elm
+ const parentElm = nodeOps.parentNode(oldElm)
+
+ // create new node
+ createElm(
+ vnode,
+ insertedVnodeQueue,
+ // extremely rare edge case: do not insert if old element is in a
+ // leaving transition. Only happens when combining transition +
+ // keep-alive + HOCs. (#4590)
+ oldElm._leaveCb ? null : parentElm,
+ nodeOps.nextSibling(oldElm)
+ )
+
+ // update parent placeholder node element, recursively
+ if (isDef(vnode.parent)) {
+ let ancestor = vnode.parent
+ const patchable = isPatchable(vnode)
+ while (ancestor) {
+ for (let i = 0; i < cbs.destroy.length; ++i) {
+ cbs.destroy[i](ancestor)
+ }
+ ancestor.elm = vnode.elm
+ if (patchable) {
+ for (let i = 0; i < cbs.create.length; ++i) {
+ cbs.create[i](emptyNode, ancestor)
+ }
+ // #6513
+ // invoke insert hooks that may have been merged by create hooks.
+ // e.g. for directives that uses the "inserted" hook.
+ const insert = ancestor.data.hook.insert
+ if (insert.merged) {
+ // start at index 1 to avoid re-invoking component mounted hook
+ for (let i = 1; i < insert.fns.length; i++) {
+ insert.fns[i]()
+ }
+ }
+ } else {
+ registerRef(ancestor)
+ }
+ ancestor = ancestor.parent
+ }
+ }
+
+ // destroy old node
+ if (isDef(parentElm)) {
+ removeVnodes(parentElm, [oldVnode], 0, 0)
+ } else if (isDef(oldVnode.tag)) {
+ invokeDestroyHook(oldVnode)
+ }
+ }
+ }
+
+ invokeInsertHook(vnode, insertedVnodeQueue, isInitialPatch)
+ return vnode.elm
+ }
+}
diff --git a/node_modules/vue/src/core/vdom/vnode.js b/node_modules/vue/src/core/vdom/vnode.js
new file mode 100644
index 00000000..88e80cec
--- /dev/null
+++ b/node_modules/vue/src/core/vdom/vnode.js
@@ -0,0 +1,108 @@
+/* @flow */
+
+export default class VNode {
+ tag: string | void;
+ data: VNodeData | void;
+ children: ?Array<VNode>;
+ text: string | void;
+ elm: Node | void;
+ ns: string | void;
+ context: Component | void; // rendered in this component's scope
+ key: string | number | void;
+ componentOptions: VNodeComponentOptions | void;
+ componentInstance: Component | void; // component instance
+ parent: VNode | void; // component placeholder node
+
+ // strictly internal
+ raw: boolean; // contains raw HTML? (server only)
+ isStatic: boolean; // hoisted static node
+ isRootInsert: boolean; // necessary for enter transition check
+ isComment: boolean; // empty comment placeholder?
+ isCloned: boolean; // is a cloned node?
+ isOnce: boolean; // is a v-once node?
+ asyncFactory: Function | void; // async component factory function
+ asyncMeta: Object | void;
+ isAsyncPlaceholder: boolean;
+ ssrContext: Object | void;
+ fnContext: Component | void; // real context vm for functional nodes
+ fnOptions: ?ComponentOptions; // for SSR caching
+ fnScopeId: ?string; // functional scope id support
+
+ constructor (
+ tag?: string,
+ data?: VNodeData,
+ children?: ?Array<VNode>,
+ text?: string,
+ elm?: Node,
+ context?: Component,
+ componentOptions?: VNodeComponentOptions,
+ asyncFactory?: Function
+ ) {
+ this.tag = tag
+ this.data = data
+ this.children = children
+ this.text = text
+ this.elm = elm
+ this.ns = undefined
+ this.context = context
+ this.fnContext = undefined
+ this.fnOptions = undefined
+ this.fnScopeId = undefined
+ this.key = data && data.key
+ this.componentOptions = componentOptions
+ this.componentInstance = undefined
+ this.parent = undefined
+ this.raw = false
+ this.isStatic = false
+ this.isRootInsert = true
+ this.isComment = false
+ this.isCloned = false
+ this.isOnce = false
+ this.asyncFactory = asyncFactory
+ this.asyncMeta = undefined
+ this.isAsyncPlaceholder = false
+ }
+
+ // DEPRECATED: alias for componentInstance for backwards compat.
+ /* istanbul ignore next */
+ get child (): Component | void {
+ return this.componentInstance
+ }
+}
+
+export const createEmptyVNode = (text: string = '') => {
+ const node = new VNode()
+ node.text = text
+ node.isComment = true
+ return node
+}
+
+export function createTextVNode (val: string | number) {
+ return new VNode(undefined, undefined, undefined, String(val))
+}
+
+// optimized shallow clone
+// used for static nodes and slot nodes because they may be reused across
+// multiple renders, cloning them avoids errors when DOM manipulations rely
+// on their elm reference.
+export function cloneVNode (vnode: VNode): VNode {
+ const cloned = new VNode(
+ vnode.tag,
+ vnode.data,
+ vnode.children,
+ vnode.text,
+ vnode.elm,
+ vnode.context,
+ vnode.componentOptions,
+ vnode.asyncFactory
+ )
+ cloned.ns = vnode.ns
+ cloned.isStatic = vnode.isStatic
+ cloned.key = vnode.key
+ cloned.isComment = vnode.isComment
+ cloned.fnContext = vnode.fnContext
+ cloned.fnOptions = vnode.fnOptions
+ cloned.fnScopeId = vnode.fnScopeId
+ cloned.isCloned = true
+ return cloned
+}