modified .gitignore

This commit is contained in:
TLRZ Seyfferth
2017-09-13 10:20:31 +02:00
parent e1db4792aa
commit cf899d0675
411 changed files with 23733 additions and 67956 deletions
+7 -5
View File
@@ -5,14 +5,16 @@ import { getFirstComponentChild } from 'core/vdom/helpers/index'
type VNodeCache = { [key: string]: ?VNode };
const patternTypes: Array<Function> = [String, RegExp]
const patternTypes: Array<Function> = [String, RegExp, Array]
function getComponentName (opts: ?VNodeComponentOptions): ?string {
return opts && (opts.Ctor.options.name || opts.tag)
}
function matches (pattern: string | RegExp, name: string): boolean {
if (typeof pattern === 'string') {
function matches (pattern: string | RegExp | Array<string>, name: string): boolean {
if (Array.isArray(pattern)) {
return pattern.indexOf(name) > -1
} else if (typeof pattern === 'string') {
return pattern.split(',').indexOf(name) > -1
} else if (isRegExp(pattern)) {
return pattern.test(name)
@@ -62,10 +64,10 @@ export default {
},
watch: {
include (val: string | RegExp) {
include (val: string | RegExp | Array<string>) {
pruneCache(this.cache, this._vnode, name => matches(val, name))
},
exclude (val: string | RegExp) {
exclude (val: string | RegExp | Array<string>) {
pruneCache(this.cache, this._vnode, name => !matches(val, name))
}
},
+6
View File
@@ -16,6 +16,7 @@ export type Config = {
performance: boolean;
devtools: boolean;
errorHandler: ?(err: Error, vm: Component, info: string) => void;
warnHandler: ?(msg: string, vm: Component, trace: string) => void;
ignoredElements: Array<string>;
keyCodes: { [key: string]: number | Array<number> };
@@ -62,6 +63,11 @@ export default ({
*/
errorHandler: null,
/**
* Warn handler for watcher warns
*/
warnHandler: null,
/**
* Ignore certain custom elements
*/
+4 -3
View File
@@ -4,10 +4,11 @@ import { toArray } from '../util/index'
export function initUse (Vue: GlobalAPI) {
Vue.use = function (plugin: Function | Object) {
/* istanbul ignore if */
if (plugin.installed) {
const installedPlugins = (this._installedPlugins || (this._installedPlugins = []))
if (installedPlugins.indexOf(plugin) > -1) {
return this
}
// additional parameters
const args = toArray(arguments, 1)
args.unshift(this)
@@ -16,7 +17,7 @@ export function initUse (Vue: GlobalAPI) {
} else if (typeof plugin === 'function') {
plugin.apply(null, args)
}
plugin.installed = true
installedPlugins.push(plugin)
return this
}
}
+1 -1
View File
@@ -11,7 +11,7 @@ Object.defineProperty(Vue.prototype, '$isServer', {
Object.defineProperty(Vue.prototype, '$ssrContext', {
get () {
/* istanbul ignore next */
return this.$vnode.ssrContext
return this.$vnode && this.$vnode.ssrContext
}
})
+22 -10
View File
@@ -1,7 +1,13 @@
/* @flow */
import {
tip,
toArray,
hyphenate,
handleError,
formatComponentName
} from '../util/index'
import { updateListeners } from '../vdom/helpers/index'
import { toArray, tip, hyphenate, formatComponentName } from '../util/index'
export function initEvents (vm: Component) {
vm._events = Object.create(null)
@@ -89,14 +95,16 @@ export function eventsMixin (Vue: Class<Component>) {
vm._events[event] = null
return vm
}
// specific handler
let cb
let i = cbs.length
while (i--) {
cb = cbs[i]
if (cb === fn || cb.fn === fn) {
cbs.splice(i, 1)
break
if (fn) {
// specific handler
let cb
let i = cbs.length
while (i--) {
cb = cbs[i]
if (cb === fn || cb.fn === fn) {
cbs.splice(i, 1)
break
}
}
}
return vm
@@ -121,7 +129,11 @@ export function eventsMixin (Vue: Class<Component>) {
cbs = cbs.length > 1 ? toArray(cbs) : cbs
const args = toArray(arguments, 1)
for (let i = 0, l = cbs.length; i < l; i++) {
cbs[i].apply(vm, args)
try {
cbs[i].apply(vm, args)
} catch (e) {
handleError(e, vm, `event handler for "${event}"`)
}
}
}
return vm
+13 -9
View File
@@ -1,8 +1,8 @@
/* @flow */
import { hasSymbol } from 'core/util/env'
import { warn } from '../util/index'
import { defineReactive } from '../observer/index'
import { hasSymbol } from 'core/util/env'
import { defineReactive, observerState } from '../observer/index'
export function initProvide (vm: Component) {
const provide = vm.$options.provide
@@ -16,6 +16,7 @@ export function initProvide (vm: Component) {
export function initInjections (vm: Component) {
const result = resolveInject(vm.$options.inject, vm)
if (result) {
observerState.shouldConvert = false
Object.keys(result).forEach(key => {
/* istanbul ignore else */
if (process.env.NODE_ENV !== 'production') {
@@ -31,24 +32,24 @@ export function initInjections (vm: Component) {
defineReactive(vm, key, result[key])
}
})
observerState.shouldConvert = true
}
}
export function resolveInject (inject: any, vm: Component): ?Object {
if (inject) {
// inject is :any because flow is not smart enough to figure out cached
// isArray here
const isArray = Array.isArray(inject)
const result = Object.create(null)
const keys = isArray
? inject
: hasSymbol
? Reflect.ownKeys(inject)
const keys = hasSymbol
? Reflect.ownKeys(inject).filter(key => {
/* istanbul ignore next */
return Object.getOwnPropertyDescriptor(inject, key).enumerable
})
: Object.keys(inject)
for (let i = 0; i < keys.length; i++) {
const key = keys[i]
const provideKey = isArray ? key : inject[key]
const provideKey = inject[key]
let source = vm
while (source) {
if (source._provided && provideKey in source._provided) {
@@ -57,6 +58,9 @@ export function resolveInject (inject: any, vm: Component): ?Object {
}
source = source.$parent
}
if (process.env.NODE_ENV !== 'production' && !source) {
warn(`Injection "${key}" not found`, vm)
}
}
return result
}
+20 -8
View File
@@ -18,6 +18,7 @@ import {
} from '../util/index'
export let activeInstance: any = null
export let isUpdatingChildComponent: boolean = false
export function initLifecycle (vm: Component) {
const options = vm.$options
@@ -65,6 +66,9 @@ export function lifecycleMixin (Vue: Class<Component>) {
vm.$options._parentElm,
vm.$options._refElm
)
// no need for the ref nodes after initial patch
// this prevents keeping a detached DOM tree in memory (#5851)
vm.$options._parentElm = vm.$options._refElm = null
} else {
// updates
vm.$el = vm.__patch__(prevVnode, vnode)
@@ -129,8 +133,6 @@ export function lifecycleMixin (Vue: Class<Component>) {
if (vm.$el) {
vm.$el.__vue__ = null
}
// remove reference to DOM nodes (prevents leak)
vm.$options._parentElm = vm.$options._refElm = null
}
}
@@ -206,6 +208,10 @@ export function updateChildComponent (
parentVnode: VNode,
renderChildren: ?Array<VNode>
) {
if (process.env.NODE_ENV !== 'production') {
isUpdatingChildComponent = true
}
// determine whether component has slot children
// we need to do this before overwriting $options._renderChildren
const hasChildren = !!(
@@ -217,17 +223,21 @@ export function updateChildComponent (
vm.$options._parentVnode = parentVnode
vm.$vnode = parentVnode // update vm's placeholder node without re-render
if (vm._vnode) { // update child tree's parent
vm._vnode.parent = parentVnode
}
vm.$options._renderChildren = renderChildren
// update $attrs and $listeners hash
// these are also reactive so they may trigger child update if the child
// used them during render
vm.$attrs = (parentVnode.data && parentVnode.data.attrs) || emptyObject
vm.$listeners = listeners || emptyObject
// update props
if (propsData && vm.$options.props) {
observerState.shouldConvert = false
if (process.env.NODE_ENV !== 'production') {
observerState.isSettingProps = true
}
const props = vm._props
const propKeys = vm.$options._propKeys || []
for (let i = 0; i < propKeys.length; i++) {
@@ -235,12 +245,10 @@ export function updateChildComponent (
props[key] = validateProp(key, vm.$options.props, propsData, vm)
}
observerState.shouldConvert = true
if (process.env.NODE_ENV !== 'production') {
observerState.isSettingProps = false
}
// keep a copy of raw propsData
vm.$options.propsData = propsData
}
// update listeners
if (listeners) {
const oldListeners = vm.$options._parentListeners
@@ -252,6 +260,10 @@ export function updateChildComponent (
vm.$slots = resolveSlots(renderChildren, parentVnode.context)
vm.$forceUpdate()
}
if (process.env.NODE_ENV !== 'production') {
isUpdatingChildComponent = false
}
}
function isInInactiveTree (vm) {
+21 -3
View File
@@ -1,7 +1,13 @@
/* @flow */
import config from 'core/config'
import { isObject, warn, toObject } from 'core/util/index'
import {
warn,
isObject,
toObject,
isReservedAttribute
} from 'core/util/index'
/**
* Runtime helper for merging v-bind="object" into a VNode's data.
@@ -10,7 +16,8 @@ export function bindObjectProps (
data: any,
tag: string,
value: any,
asProp?: boolean
asProp: boolean,
isSync?: boolean
): VNodeData {
if (value) {
if (!isObject(value)) {
@@ -24,7 +31,11 @@ export function bindObjectProps (
}
let hash
for (const key in value) {
if (key === 'class' || key === 'style') {
if (
key === 'class' ||
key === 'style' ||
isReservedAttribute(key)
) {
hash = data
} else {
const type = data.attrs && data.attrs.type
@@ -34,6 +45,13 @@ export function bindObjectProps (
}
if (!(key in hash)) {
hash[key] = value[key]
if (isSync) {
const on = data.on || (data.on = {})
on[`update:${key}`] = function ($event) {
value[key] = $event
}
}
}
}
}
+5 -1
View File
@@ -7,7 +7,11 @@ import { isObject, isDef } from 'core/util/index'
*/
export function renderList (
val: any,
render: () => VNode
render: (
val: any,
keyOrIndex: string | number,
index?: number
) => VNode
): ?Array<VNode> {
let ret: ?Array<VNode>, i, l, keys, key
if (Array.isArray(val) || typeof val === 'string') {
+1 -1
View File
@@ -15,7 +15,7 @@ export function renderSlot (
if (scopedSlotFn) { // scoped slot
props = props || {}
if (bindObject) {
extend(props, bindObject)
props = extend(extend({}, bindObject), props)
}
return scopedSlotFn(props) || fallback
} else {
+6 -1
View File
@@ -14,10 +14,15 @@ export function resolveSlots (
const defaultSlot = []
for (let i = 0, l = children.length; i < l; i++) {
const child = children[i]
const data = child.data
// remove slot attribute if the node is resolved as a Vue slot node
if (data && data.attrs && data.attrs.slot) {
delete data.attrs.slot
}
// named slots should only be respected if the vnode was rendered in the
// same context.
if ((child.context === context || child.functionalContext === context) &&
child.data && child.data.slot != null
data && data.slot != null
) {
const name = child.data.slot
const slot = (slots[name] || (slots[name] = []))
+29 -3
View File
@@ -8,7 +8,8 @@ import {
looseEqual,
emptyObject,
handleError,
looseIndexOf
looseIndexOf,
defineReactive
} from '../util/index'
import VNode, {
@@ -17,6 +18,8 @@ import VNode, {
createEmptyVNode
} from '../vdom/vnode'
import { isUpdatingChildComponent } from './lifecycle'
import { createElement } from '../vdom/create-element'
import { renderList } from './render-helpers/render-list'
import { renderSlot } from './render-helpers/render-slot'
@@ -24,6 +27,7 @@ import { resolveFilter } from './render-helpers/resolve-filter'
import { checkKeyCodes } from './render-helpers/check-keycodes'
import { bindObjectProps } from './render-helpers/bind-object-props'
import { renderStatic, markOnce } from './render-helpers/render-static'
import { bindObjectListeners } from './render-helpers/bind-object-listeners'
import { resolveSlots, resolveScopedSlots } from './render-helpers/resolve-slots'
export function initRender (vm: Component) {
@@ -41,6 +45,23 @@ export function initRender (vm: Component) {
// normalization is always applied for the public version, used in
// user-written render functions.
vm.$createElement = (a, b, c, d) => createElement(vm, a, b, c, d, true)
// $attrs & $listeners are exposed for easier HOC creation.
// they need to be reactive so that HOCs using them are always updated
const parentData = parentVnode && parentVnode.data
/* istanbul ignore else */
if (process.env.NODE_ENV !== 'production') {
defineReactive(vm, '$attrs', parentData && parentData.attrs || emptyObject, () => {
!isUpdatingChildComponent && warn(`$attrs is readonly.`, vm)
}, true)
defineReactive(vm, '$listeners', vm.$options._parentListeners || emptyObject, () => {
!isUpdatingChildComponent && warn(`$listeners is readonly.`, vm)
}, true)
} else {
defineReactive(vm, '$attrs', parentData && parentData.attrs || emptyObject, null, true)
defineReactive(vm, '$listeners', vm.$options._parentListeners || emptyObject, null, true)
}
}
export function renderMixin (Vue: Class<Component>) {
@@ -57,9 +78,13 @@ export function renderMixin (Vue: Class<Component>) {
} = vm.$options
if (vm._isMounted) {
// clone slot nodes on re-renders
// if the parent didn't update, the slot nodes will be the ones from
// last render. They need to be cloned to ensure "freshness" for this render.
for (const key in vm.$slots) {
vm.$slots[key] = cloneVNodes(vm.$slots[key])
const slot = vm.$slots[key]
if (slot._rendered) {
vm.$slots[key] = cloneVNodes(slot, true /* deep */)
}
}
}
@@ -121,4 +146,5 @@ export function renderMixin (Vue: Class<Component>) {
Vue.prototype._v = createTextVNode
Vue.prototype._e = createEmptyVNode
Vue.prototype._u = resolveScopedSlots
Vue.prototype._g = bindObjectListeners
}
+92 -33
View File
@@ -3,6 +3,7 @@
import config from '../config'
import Dep from '../observer/dep'
import Watcher from '../observer/watcher'
import { isUpdatingChildComponent } from './lifecycle'
import {
set,
@@ -19,8 +20,11 @@ import {
hasOwn,
isReserved,
handleError,
nativeWatch,
validateProp,
isPlainObject
isPlainObject,
isServerRendering,
isReservedAttribute
} from '../util/index'
const sharedPropertyDefinition = {
@@ -51,13 +55,19 @@ export function initState (vm: Component) {
observe(vm._data = {}, true /* asRootData */)
}
if (opts.computed) initComputed(vm, opts.computed)
if (opts.watch) initWatch(vm, opts.watch)
if (opts.watch && opts.watch !== nativeWatch) {
initWatch(vm, opts.watch)
}
}
const isReservedProp = {
key: 1,
ref: 1,
slot: 1
function checkOptionType (vm: Component, name: string) {
const option = vm.$options[name]
if (!isPlainObject(option)) {
warn(
`component option "${name}" should be an object.`,
vm
)
}
}
function initProps (vm: Component, propsOptions: Object) {
@@ -74,14 +84,14 @@ function initProps (vm: Component, propsOptions: Object) {
const value = validateProp(key, propsOptions, propsData, vm)
/* istanbul ignore else */
if (process.env.NODE_ENV !== 'production') {
if (isReservedProp[key] || config.isReservedAttr(key)) {
if (isReservedAttribute(key) || config.isReservedAttr(key)) {
warn(
`"${key}" is a reserved attribute and cannot be used as component prop.`,
vm
)
}
defineReactive(props, key, value, () => {
if (vm.$parent && !observerState.isSettingProps) {
if (vm.$parent && !isUpdatingChildComponent) {
warn(
`Avoid mutating a prop directly since the value will be ` +
`overwritten whenever the parent component re-renders. ` +
@@ -120,16 +130,26 @@ function initData (vm: Component) {
// proxy data on instance
const keys = Object.keys(data)
const props = vm.$options.props
const methods = vm.$options.methods
let i = keys.length
while (i--) {
if (props && hasOwn(props, keys[i])) {
const key = keys[i]
if (process.env.NODE_ENV !== 'production') {
if (methods && hasOwn(methods, key)) {
warn(
`Method "${key}" has already been defined as a data property.`,
vm
)
}
}
if (props && hasOwn(props, key)) {
process.env.NODE_ENV !== 'production' && warn(
`The data property "${keys[i]}" is already declared as a prop. ` +
`The data property "${key}" is already declared as a prop. ` +
`Use prop default value instead.`,
vm
)
} else if (!isReserved(keys[i])) {
proxy(vm, `_data`, keys[i])
} else if (!isReserved(key)) {
proxy(vm, `_data`, key)
}
}
// observe data
@@ -148,22 +168,30 @@ function getData (data: Function, vm: Component): any {
const computedWatcherOptions = { lazy: true }
function initComputed (vm: Component, computed: Object) {
process.env.NODE_ENV !== 'production' && checkOptionType(vm, 'computed')
const watchers = vm._computedWatchers = Object.create(null)
// computed properties are just getters during SSR
const isSSR = isServerRendering()
for (const key in computed) {
const userDef = computed[key]
let getter = typeof userDef === 'function' ? userDef : userDef.get
if (process.env.NODE_ENV !== 'production') {
if (getter === undefined) {
warn(
`No getter function has been defined for computed property "${key}".`,
vm
)
getter = noop
}
const getter = typeof userDef === 'function' ? userDef : userDef.get
if (process.env.NODE_ENV !== 'production' && getter == null) {
warn(
`Getter is missing for computed property "${key}".`,
vm
)
}
if (!isSSR) {
// create internal watcher for the computed property.
watchers[key] = new Watcher(
vm,
getter || noop,
noop,
computedWatcherOptions
)
}
// create internal watcher for the computed property.
watchers[key] = new Watcher(vm, getter, noop, computedWatcherOptions)
// component-defined computed properties are already defined on the
// component prototype. We only need to define computed properties defined
@@ -180,13 +208,20 @@ function initComputed (vm: Component, computed: Object) {
}
}
export function defineComputed (target: any, key: string, userDef: Object | Function) {
export function defineComputed (
target: any,
key: string,
userDef: Object | Function
) {
const shouldCache = !isServerRendering()
if (typeof userDef === 'function') {
sharedPropertyDefinition.get = createComputedGetter(key)
sharedPropertyDefinition.get = shouldCache
? createComputedGetter(key)
: userDef
sharedPropertyDefinition.set = noop
} else {
sharedPropertyDefinition.get = userDef.get
? userDef.cache !== false
? shouldCache && userDef.cache !== false
? createComputedGetter(key)
: userDef.get
: noop
@@ -194,6 +229,15 @@ export function defineComputed (target: any, key: string, userDef: Object | Func
? userDef.set
: noop
}
if (process.env.NODE_ENV !== 'production' &&
sharedPropertyDefinition.set === noop) {
sharedPropertyDefinition.set = function () {
warn(
`Computed property "${key}" was assigned to but it has no setter.`,
this
)
}
}
Object.defineProperty(target, key, sharedPropertyDefinition)
}
@@ -213,28 +257,36 @@ function createComputedGetter (key) {
}
function initMethods (vm: Component, methods: Object) {
process.env.NODE_ENV !== 'production' && checkOptionType(vm, 'methods')
const props = vm.$options.props
for (const key in methods) {
vm[key] = methods[key] == null ? noop : bind(methods[key], vm)
if (process.env.NODE_ENV !== 'production') {
if (methods[key] == null) {
warn(
`method "${key}" has an undefined value in the component definition. ` +
`Method "${key}" has an undefined value in the component definition. ` +
`Did you reference the function correctly?`,
vm
)
}
if (props && hasOwn(props, key)) {
warn(
`method "${key}" has already been defined as a prop.`,
`Method "${key}" has already been defined as a prop.`,
vm
)
}
if ((key in vm) && isReserved(key)) {
warn(
`Method "${key}" conflicts with an existing Vue instance method. ` +
`Avoid defining component methods that start with _ or $.`
)
}
}
vm[key] = methods[key] == null ? noop : bind(methods[key], vm)
}
}
function initWatch (vm: Component, watch: Object) {
process.env.NODE_ENV !== 'production' && checkOptionType(vm, 'watch')
for (const key in watch) {
const handler = watch[key]
if (Array.isArray(handler)) {
@@ -247,8 +299,12 @@ function initWatch (vm: Component, watch: Object) {
}
}
function createWatcher (vm: Component, key: string, handler: any) {
let options
function createWatcher (
vm: Component,
keyOrFn: string | Function,
handler: any,
options?: Object
) {
if (isPlainObject(handler)) {
options = handler
handler = handler.handler
@@ -256,7 +312,7 @@ function createWatcher (vm: Component, key: string, handler: any) {
if (typeof handler === 'string') {
handler = vm[handler]
}
vm.$watch(key, handler, options)
return vm.$watch(keyOrFn, handler, options)
}
export function stateMixin (Vue: Class<Component>) {
@@ -287,10 +343,13 @@ export function stateMixin (Vue: Class<Component>) {
Vue.prototype.$watch = function (
expOrFn: string | Function,
cb: Function,
cb: any,
options?: Object
): Function {
const vm: Component = this
if (isPlainObject(cb)) {
return createWatcher(vm, expOrFn, cb, options)
}
options = options || {}
options.user = true
const watcher = new Watcher(vm, expOrFn, cb, options)
+1 -10
View File
@@ -23,21 +23,12 @@ export const arrayMethods = Object.create(arrayProto)
.forEach(function (method) {
// cache original method
const original = arrayProto[method]
def(arrayMethods, method, function mutator () {
// avoid leaking arguments:
// http://jsperf.com/closure-with-arguments
let i = arguments.length
const args = new Array(i)
while (i--) {
args[i] = arguments[i]
}
def(arrayMethods, method, function mutator (...args) {
const result = original.apply(this, args)
const ob = this.__ob__
let inserted
switch (method) {
case 'push':
inserted = args
break
case 'unshift':
inserted = args
break
+17 -16
View File
@@ -4,11 +4,12 @@ import Dep from './dep'
import { arrayMethods } from './array'
import {
def,
warn,
hasOwn,
hasProto,
isObject,
isPlainObject,
hasProto,
hasOwn,
warn,
isValidArrayIndex,
isServerRendering
} from '../util/index'
@@ -21,8 +22,7 @@ const arrayKeys = Object.getOwnPropertyNames(arrayMethods)
* under a frozen data structure. Converting it would defeat the optimization.
*/
export const observerState = {
shouldConvert: true,
isSettingProps: false
shouldConvert: true
}
/**
@@ -80,7 +80,7 @@ export class Observer {
* Augment an target Object or Array by intercepting
* the prototype chain using __proto__
*/
function protoAugment (target, src: Object) {
function protoAugment (target, src: Object, keys: any) {
/* eslint-disable no-proto */
target.__proto__ = src
/* eslint-enable no-proto */
@@ -132,7 +132,8 @@ export function defineReactive (
obj: Object,
key: string,
val: any,
customSetter?: Function
customSetter?: ?Function,
shallow?: boolean
) {
const dep = new Dep()
@@ -145,7 +146,7 @@ export function defineReactive (
const getter = property && property.get
const setter = property && property.set
let childOb = observe(val)
let childOb = !shallow && observe(val)
Object.defineProperty(obj, key, {
enumerable: true,
configurable: true,
@@ -155,9 +156,9 @@ export function defineReactive (
dep.depend()
if (childOb) {
childOb.dep.depend()
}
if (Array.isArray(value)) {
dependArray(value)
if (Array.isArray(value)) {
dependArray(value)
}
}
}
return value
@@ -177,7 +178,7 @@ export function defineReactive (
} else {
val = newVal
}
childOb = observe(newVal)
childOb = !shallow && observe(newVal)
dep.notify()
}
})
@@ -189,7 +190,7 @@ export function defineReactive (
* already exist.
*/
export function set (target: Array<any> | Object, key: any, val: any): any {
if (Array.isArray(target) && typeof key === 'number') {
if (Array.isArray(target) && isValidArrayIndex(key)) {
target.length = Math.max(target.length, key)
target.splice(key, 1, val)
return val
@@ -198,7 +199,7 @@ export function set (target: Array<any> | Object, key: any, val: any): any {
target[key] = val
return val
}
const ob = (target : any).__ob__
const ob = (target: any).__ob__
if (target._isVue || (ob && ob.vmCount)) {
process.env.NODE_ENV !== 'production' && warn(
'Avoid adding reactive properties to a Vue instance or its root $data ' +
@@ -219,11 +220,11 @@ export function set (target: Array<any> | Object, key: any, val: any): any {
* Delete a property and trigger change if necessary.
*/
export function del (target: Array<any> | Object, key: any) {
if (Array.isArray(target) && typeof key === 'number') {
if (Array.isArray(target) && isValidArrayIndex(key)) {
target.splice(key, 1)
return
}
const ob = (target : any).__ob__
const ob = (target: any).__ob__
if (target._isVue || (ob && ob.vmCount)) {
process.env.NODE_ENV !== 'production' && warn(
'Avoid deleting properties on a Vue instance or its root $data ' +
+2 -2
View File
@@ -81,7 +81,7 @@ function flushSchedulerQueue () {
// call component updated and activated hooks
callActivatedHooks(activatedQueue)
callUpdateHooks(updatedQueue)
callUpdatedHooks(updatedQueue)
// devtool hook
/* istanbul ignore if */
@@ -90,7 +90,7 @@ function flushSchedulerQueue () {
}
}
function callUpdateHooks (queue) {
function callUpdatedHooks (queue) {
let i = queue.length
while (i--) {
const watcher = queue[i]
+15 -14
View File
@@ -94,22 +94,23 @@ export default class Watcher {
pushTarget(this)
let value
const vm = this.vm
if (this.user) {
try {
value = this.getter.call(vm, vm)
} catch (e) {
handleError(e, vm, `getter for watcher "${this.expression}"`)
}
} else {
try {
value = this.getter.call(vm, vm)
} catch (e) {
if (this.user) {
handleError(e, vm, `getter for watcher "${this.expression}"`)
} else {
throw e
}
} finally {
// "touch" every property so they are all tracked as
// dependencies for deep watching
if (this.deep) {
traverse(value)
}
popTarget()
this.cleanupDeps()
}
// "touch" every property so they are all tracked as
// dependencies for deep watching
if (this.deep) {
traverse(value)
}
popTarget()
this.cleanupDeps()
return value
}
+6 -4
View File
@@ -15,10 +15,12 @@ if (process.env.NODE_ENV !== 'production') {
.replace(/[-_]/g, '')
warn = (msg, vm) => {
if (hasConsole && (!config.silent)) {
console.error(`[Vue warn]: ${msg}` + (
vm ? generateComponentTrace(vm) : ''
))
const trace = vm ? generateComponentTrace(vm) : ''
if (config.warnHandler) {
config.warnHandler.call(null, msg, vm, trace)
} else if (hasConsole && (!config.silent)) {
console.error(`[Vue warn]: ${msg}${trace}`)
}
}
+6 -3
View File
@@ -17,6 +17,9 @@ export const isAndroid = UA && UA.indexOf('android') > 0
export const isIOS = UA && /iphone|ipad|ipod|ios/.test(UA)
export const isChrome = UA && /chrome\/\d+/.test(UA) && !isEdge
// Firefox has a "watch" function on Object.prototype...
export const nativeWatch = ({}).watch
export let supportsPassive = false
if (inBrowser) {
try {
@@ -26,7 +29,7 @@ if (inBrowser) {
/* istanbul ignore next */
supportsPassive = true
}
} : Object)) // https://github.com/facebook/flow/issues/285
}: Object)) // https://github.com/facebook/flow/issues/285
window.addEventListener('test-passive', null, opts)
} catch (e) {}
}
@@ -96,13 +99,13 @@ export const nextTick = (function () {
// "force" the microtask queue to be flushed by adding an empty timer.
if (isIOS) setTimeout(noop)
}
} else if (typeof MutationObserver !== 'undefined' && (
} else if (!isIE && typeof MutationObserver !== 'undefined' && (
isNative(MutationObserver) ||
// PhantomJS and iOS 7.x
MutationObserver.toString() === '[object MutationObserverConstructor]'
)) {
// use MutationObserver where native Promise is not available,
// e.g. PhantomJS IE11, iOS7, Android 4.4
// e.g. PhantomJS, iOS7, Android 4.4
var counter = 1
var observer = new MutationObserver(nextTickHandler)
var textNode = document.createTextNode(String(counter))
+48 -16
View File
@@ -2,6 +2,7 @@
import config from '../config'
import { warn } from './debug'
import { nativeWatch } from './env'
import { set } from '../observer/index'
import {
@@ -63,7 +64,7 @@ function mergeData (to: Object, from: ?Object): Object {
/**
* Data
*/
strats.data = function (
export function mergeDataOrFn (
parentVal: any,
childVal: any,
vm?: Component
@@ -73,15 +74,6 @@ strats.data = function (
if (!childVal) {
return parentVal
}
if (typeof childVal !== 'function') {
process.env.NODE_ENV !== 'production' && warn(
'The "data" option should be a function ' +
'that returns a per-instance value in component ' +
'definitions.',
vm
)
return parentVal
}
if (!parentVal) {
return childVal
}
@@ -92,8 +84,8 @@ strats.data = function (
// it has to be a function to pass previous merges.
return function mergedDataFn () {
return mergeData(
childVal.call(this),
parentVal.call(this)
typeof childVal === 'function' ? childVal.call(this) : childVal,
typeof parentVal === 'function' ? parentVal.call(this) : parentVal
)
}
} else if (parentVal || childVal) {
@@ -104,7 +96,7 @@ strats.data = function (
: childVal
const defaultData = typeof parentVal === 'function'
? parentVal.call(vm)
: undefined
: parentVal
if (instanceData) {
return mergeData(instanceData, defaultData)
} else {
@@ -114,6 +106,28 @@ strats.data = function (
}
}
strats.data = function (
parentVal: any,
childVal: any,
vm?: Component
): ?Function {
if (!vm) {
if (childVal && typeof childVal !== 'function') {
process.env.NODE_ENV !== 'production' && warn(
'The "data" option should be a function ' +
'that returns a per-instance value in component ' +
'definitions.',
vm
)
return parentVal
}
return mergeDataOrFn.call(this, parentVal, childVal)
}
return mergeDataOrFn(parentVal, childVal, vm)
}
/**
* Hooks and props are merged as arrays.
*/
@@ -159,6 +173,9 @@ ASSET_TYPES.forEach(function (type) {
* another, so we merge them as arrays.
*/
strats.watch = function (parentVal: ?Object, childVal: ?Object): ?Object {
// work around Firefox's Object.prototype.watch...
if (parentVal === nativeWatch) parentVal = undefined
if (childVal === nativeWatch) childVal = undefined
/* istanbul ignore if */
if (!childVal) return Object.create(parentVal || null)
if (!parentVal) return childVal
@@ -172,7 +189,7 @@ strats.watch = function (parentVal: ?Object, childVal: ?Object): ?Object {
}
ret[key] = parent
? parent.concat(child)
: [child]
: Array.isArray(child) ? child : [child]
}
return ret
}
@@ -182,14 +199,15 @@ strats.watch = function (parentVal: ?Object, childVal: ?Object): ?Object {
*/
strats.props =
strats.methods =
strats.inject =
strats.computed = function (parentVal: ?Object, childVal: ?Object): ?Object {
if (!childVal) return Object.create(parentVal || null)
if (!parentVal) return childVal
const ret = Object.create(null)
extend(ret, parentVal)
extend(ret, childVal)
if (childVal) extend(ret, childVal)
return ret
}
strats.provide = mergeDataOrFn
/**
* Default strategy.
@@ -247,6 +265,19 @@ function normalizeProps (options: Object) {
options.props = res
}
/**
* Normalize all injections into Object-based format
*/
function normalizeInject (options: Object) {
const inject = options.inject
if (Array.isArray(inject)) {
const normalized = options.inject = {}
for (let i = 0; i < inject.length; i++) {
normalized[inject[i]] = inject[i]
}
}
}
/**
* Normalize raw function directives into object format.
*/
@@ -280,6 +311,7 @@ export function mergeOptions (
}
normalizeProps(child)
normalizeInject(child)
normalizeDirectives(child)
const extendsFrom = child.extends
if (extendsFrom) {
+14 -3
View File
@@ -1,8 +1,14 @@
/* @flow */
import { hasOwn, isObject, isPlainObject, capitalize, hyphenate } from 'shared/util'
import { observe, observerState } from '../observer/index'
import { warn } from './debug'
import { observe, observerState } from '../observer/index'
import {
hasOwn,
isObject,
hyphenate,
capitalize,
isPlainObject
} from 'shared/util'
type PropOptions = {
type: Function | Array<Function> | null,
@@ -139,7 +145,12 @@ function assertType (value: any, type: Function): {
let valid
const expectedType = getType(type)
if (simpleCheckRE.test(expectedType)) {
valid = typeof value === expectedType.toLowerCase()
const t = typeof value
valid = t === expectedType.toLowerCase()
// for primitive wrapper objects
if (!valid && t === 'object') {
valid = value instanceof type
}
} else if (expectedType === 'Object') {
valid = isPlainObject(value)
} else if (expectedType === 'Array') {
+27 -9
View File
@@ -15,6 +15,7 @@ import {
import {
resolveAsyncComponent,
createAsyncPlaceholder,
extractPropsFromVNodeData
} from './helpers/index'
@@ -97,7 +98,7 @@ const hooksToMerge = Object.keys(componentVNodeHooks)
export function createComponent (
Ctor: Class<Component> | Function | Object | void,
data?: VNodeData,
data: ?VNodeData,
context: Component,
children: ?Array<VNode>,
tag?: string
@@ -123,21 +124,30 @@ export function createComponent (
}
// async component
let asyncFactory
if (isUndef(Ctor.cid)) {
Ctor = resolveAsyncComponent(Ctor, baseCtor, context)
asyncFactory = Ctor
Ctor = resolveAsyncComponent(asyncFactory, baseCtor, context)
if (Ctor === undefined) {
// return nothing if this is indeed an async component
// wait for the callback to trigger parent update.
return
// 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)
data = data || {}
// transform component v-model data into props & events
if (isDef(data.model)) {
transformModel(Ctor.options, data)
@@ -155,12 +165,19 @@ export function createComponent (
// 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
// other than props & listeners & slot
// work around flow
const slot = data.slot
data = {}
if (slot) {
data.slot = slot
}
}
// merge component management hooks onto the placeholder node
@@ -171,7 +188,8 @@ export function createComponent (
const vnode = new VNode(
`vue-component-${Ctor.cid}${name ? `-${name}` : ''}`,
data, undefined, undefined, undefined, context,
{ Ctor, propsData, listeners, tag, children }
{ Ctor, propsData, listeners, tag, children },
asyncFactory
)
return vnode
}
+15 -1
View File
@@ -57,10 +57,24 @@ export function _createElement (
)
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)
) {
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'
@@ -77,7 +91,7 @@ export function _createElement (
let vnode, ns
if (typeof tag === 'string') {
let Ctor
ns = config.getTagNamespace(tag)
ns = (context.$vnode && context.$vnode.ns) || config.getTagNamespace(tag)
if (config.isReservedTag(tag)) {
// platform built-in elements
vnode = new VNode(
+3 -2
View File
@@ -8,6 +8,7 @@ import { resolveSlots } from '../instance/render-helpers/resolve-slots'
import {
isDef,
camelize,
emptyObject,
validateProp
} from '../util/index'
@@ -22,7 +23,7 @@ export function createFunctionalComponent (
const propOptions = Ctor.options.props
if (isDef(propOptions)) {
for (const key in propOptions) {
props[key] = validateProp(key, propOptions, propsData || {})
props[key] = validateProp(key, propOptions, propsData || emptyObject)
}
} else {
if (isDef(data.attrs)) mergeProps(props, data.attrs)
@@ -37,7 +38,7 @@ export function createFunctionalComponent (
props,
children,
parent: context,
listeners: data.on || {},
listeners: data.on || emptyObject,
injections: resolveInject(Ctor.options.inject, context),
slots: () => resolveSlots(children, context)
})
+2 -1
View File
@@ -1,12 +1,13 @@
/* @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)) {
if (isDef(c) && (isDef(c.componentOptions) || isAsyncPlaceholder(c))) {
return c
}
}
+1
View File
@@ -6,3 +6,4 @@ export * from './update-listeners'
export * from './normalize-children'
export * from './resolve-async-component'
export * from './get-first-component-child'
export * from './is-async-placeholder'
+18
View File
@@ -9,12 +9,30 @@ import {
isObject
} from 'core/util/index'
import { createEmptyVNode } from 'core/vdom/vnode'
function ensureCtor (comp, base) {
if (comp.__esModule && comp.default) {
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>,
+25 -4
View File
@@ -5,9 +5,11 @@ import { cached, isUndef } from 'shared/util'
const normalizeEvent = cached((name: string): {
name: string,
plain: boolean,
once: boolean,
capture: boolean,
passive: boolean
passive: boolean,
handler?: Function
} => {
const passive = name.charAt(0) === '&'
name = passive ? name.slice(1) : name
@@ -15,8 +17,10 @@ const normalizeEvent = cached((name: string): {
name = once ? name.slice(1) : name
const capture = name.charAt(0) === '!'
name = capture ? name.slice(1) : name
const plain = !(passive || once || capture)
return {
name,
plain,
once,
capture,
passive
@@ -27,8 +31,9 @@ export function createFnInvoker (fns: Function | Array<Function>): Function {
function invoker () {
const fns = invoker.fns
if (Array.isArray(fns)) {
for (let i = 0; i < fns.length; i++) {
fns[i].apply(null, arguments)
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
@@ -39,6 +44,11 @@ export function createFnInvoker (fns: Function | Array<Function>): Function {
return invoker
}
// #6552
function prioritizePlainEvents (a, b) {
return a.plain ? -1 : b.plain ? 1 : 0
}
export function updateListeners (
on: Object,
oldOn: Object,
@@ -47,10 +57,13 @@ export function updateListeners (
vm: Component
) {
let name, cur, old, event
const toAdd = []
let hasModifier = false
for (name in on) {
cur = on[name]
old = oldOn[name]
event = normalizeEvent(name)
if (!event.plain) hasModifier = true
if (isUndef(cur)) {
process.env.NODE_ENV !== 'production' && warn(
`Invalid handler for event "${event.name}": got ` + String(cur),
@@ -60,12 +73,20 @@ export function updateListeners (
if (isUndef(cur.fns)) {
cur = on[name] = createFnInvoker(cur)
}
add(event.name, cur, event.once, event.capture, event.passive)
event.handler = cur
toAdd.push(event)
} else if (cur !== old) {
old.fns = cur
on[name] = old
}
}
if (toAdd.length) {
if (hasModifier) toAdd.sort(prioritizePlainEvents)
for (let i = 0; i < toAdd.length; i++) {
const event = toAdd[i]
add(event.name, event.handler, event.once, event.capture, event.passive)
}
}
for (name in oldOn) {
if (isUndef(on[name])) {
event = normalizeEvent(name)
+4 -3
View File
@@ -32,10 +32,11 @@ export function registerRef (vnode: VNodeWithData, isRemoval: ?boolean) {
}
} else {
if (vnode.data.refInFor) {
if (Array.isArray(refs[key]) && refs[key].indexOf(ref) < 0) {
refs[key].push(ref)
} else {
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
+103 -42
View File
@@ -6,8 +6,6 @@
*
* 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.
*/
@@ -17,6 +15,7 @@ import config from '../config'
import { SSR_ATTR } from 'shared/constants'
import { registerRef } from './modules/ref'
import { activeInstance } from '../instance/lifecycle'
import { isTextInputType } from 'web/util/element'
import {
warn,
@@ -33,22 +32,27 @@ 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)
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)
)
)
)
}
// Some browsers do not support dynamically changing type for <input>
// so they need to be treated as different nodes
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
return typeA === typeB || isTextInputType(typeA) && isTextInputType(typeB)
}
function createKeyToOldIdx (children, beginIdx, endIdx) {
@@ -397,10 +401,11 @@ export function createPatchFunction (backend) {
newStartVnode = newCh[++newStartIdx]
} else {
if (isUndef(oldKeyToIdx)) oldKeyToIdx = createKeyToOldIdx(oldCh, oldStartIdx, oldEndIdx)
idxInOld = isDef(newStartVnode.key) ? oldKeyToIdx[newStartVnode.key] : null
idxInOld = isDef(newStartVnode.key)
? oldKeyToIdx[newStartVnode.key]
: findIdxInOld(newStartVnode, oldCh, oldStartIdx, oldEndIdx)
if (isUndef(idxInOld)) { // New element
createElm(newStartVnode, insertedVnodeQueue, parentElm, oldStartVnode.elm)
newStartVnode = newCh[++newStartIdx]
} else {
elmToMove = oldCh[idxInOld]
/* istanbul ignore if */
@@ -413,14 +418,13 @@ export function createPatchFunction (backend) {
if (sameVnode(elmToMove, newStartVnode)) {
patchVnode(elmToMove, newStartVnode, insertedVnodeQueue)
oldCh[idxInOld] = undefined
canMove && nodeOps.insertBefore(parentElm, newStartVnode.elm, oldStartVnode.elm)
newStartVnode = newCh[++newStartIdx]
canMove && nodeOps.insertBefore(parentElm, elmToMove.elm, oldStartVnode.elm)
} else {
// same key but different element. treat as new element
createElm(newStartVnode, insertedVnodeQueue, parentElm, oldStartVnode.elm)
newStartVnode = newCh[++newStartIdx]
}
}
newStartVnode = newCh[++newStartIdx]
}
}
if (oldStartIdx > oldEndIdx) {
@@ -431,10 +435,29 @@ export function createPatchFunction (backend) {
}
}
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
@@ -444,16 +467,16 @@ export function createPatchFunction (backend) {
vnode.key === oldVnode.key &&
(isTrue(vnode.isCloned) || isTrue(vnode.isOnce))
) {
vnode.elm = oldVnode.elm
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 elm = vnode.elm = oldVnode.elm
const oldCh = oldVnode.children
const ch = vnode.children
if (isDef(data) && isPatchable(vnode)) {
@@ -498,6 +521,11 @@ export function createPatchFunction (backend) {
// Note: this is a browser-only function so we can assume elms are DOM nodes.
function hydrate (elm, vnode, insertedVnodeQueue) {
if (isTrue(vnode.isComment) && isDef(vnode.asyncFactory)) {
vnode.elm = elm
vnode.isAsyncPlaceholder = true
return true
}
if (process.env.NODE_ENV !== 'production') {
if (!assertNodeMatch(elm, vnode)) {
return false
@@ -519,27 +547,46 @@ export function createPatchFunction (backend) {
if (!elm.hasChildNodes()) {
createChildren(vnode, children, insertedVnodeQueue)
} else {
let childrenMatch = true
let childNode = elm.firstChild
for (let i = 0; i < children.length; i++) {
if (!childNode || !hydrate(childNode, children[i], insertedVnodeQueue)) {
childrenMatch = false
break
// 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' &&
!bailed
) {
bailed = true
console.warn('Parent: ', elm)
console.warn('server innerHTML: ', i)
console.warn('client innerHTML: ', elm.innerHTML)
}
return false
}
childNode = childNode.nextSibling
}
// if childNode is not null, it means the actual childNodes list is
// longer than the virtual children list.
if (!childrenMatch || childNode) {
if (process.env.NODE_ENV !== 'production' &&
typeof console !== 'undefined' &&
!bailed
) {
bailed = true
console.warn('Parent: ', elm)
console.warn('Mismatching childNodes vs. VNodes: ', elm.childNodes, children)
} 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)) {
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' &&
!bailed
) {
bailed = true
console.warn('Parent: ', elm)
console.warn('Mismatching childNodes vs. VNodes: ', elm.childNodes, children)
}
return false
}
return false
}
}
}
@@ -630,14 +677,28 @@ export function createPatchFunction (backend) {
// component root element replaced.
// update parent placeholder node element, recursively
let ancestor = vnode.parent
const patchable = isPatchable(vnode)
while (ancestor) {
ancestor.elm = vnode.elm
ancestor = ancestor.parent
}
if (isPatchable(vnode)) {
for (let i = 0; i < cbs.create.length; ++i) {
cbs.create[i](emptyNode, vnode.parent)
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]()
}
}
}
ancestor = ancestor.parent
}
}
+19 -7
View File
@@ -19,6 +19,10 @@ export default class VNode {
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;
constructor (
tag?: string,
@@ -27,7 +31,8 @@ export default class VNode {
text?: string,
elm?: Node,
context?: Component,
componentOptions?: VNodeComponentOptions
componentOptions?: VNodeComponentOptions,
asyncFactory?: Function
) {
this.tag = tag
this.data = data
@@ -47,6 +52,9 @@ export default class VNode {
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.
@@ -56,9 +64,9 @@ export default class VNode {
}
}
export const createEmptyVNode = () => {
export const createEmptyVNode = (text: string = '') => {
const node = new VNode()
node.text = ''
node.text = text
node.isComment = true
return node
}
@@ -71,7 +79,7 @@ export function createTextVNode (val: string | number) {
// 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 {
export function cloneVNode (vnode: VNode, deep?: boolean): VNode {
const cloned = new VNode(
vnode.tag,
vnode.data,
@@ -79,21 +87,25 @@ export function cloneVNode (vnode: VNode): VNode {
vnode.text,
vnode.elm,
vnode.context,
vnode.componentOptions
vnode.componentOptions,
vnode.asyncFactory
)
cloned.ns = vnode.ns
cloned.isStatic = vnode.isStatic
cloned.key = vnode.key
cloned.isComment = vnode.isComment
cloned.isCloned = true
if (deep && vnode.children) {
cloned.children = cloneVNodes(vnode.children)
}
return cloned
}
export function cloneVNodes (vnodes: Array<VNode>): Array<VNode> {
export function cloneVNodes (vnodes: Array<VNode>, deep?: boolean): Array<VNode> {
const len = vnodes.length
const res = new Array(len)
for (let i = 0; i < len; i++) {
res[i] = cloneVNode(vnodes[i])
res[i] = cloneVNode(vnodes[i], deep)
}
return res
}