You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Vue.extend = function (extendOptions: Object): Function {
extendOptions = extendOptions || {}
const Super = this
const SuperId = Super.cid
const cachedCtors = extendOptions._Ctor || (extendOptions._Ctor = {})
if (cachedCtors[SuperId]) {
return cachedCtors[SuperId]
}
const name = extendOptions.name || Super.options.name
if (process.env.NODE_ENV !== 'production' && name) {
validateComponentName(name)
}
const Sub = function VueComponent (options) {
this._init(options)
}
Sub.prototype = Object.create(Super.prototype)
Sub.prototype.constructor = Sub
Sub.cid = cid++
Sub.options = mergeOptions(
Super.options,
extendOptions
)
Sub['super'] = Super
// For props and computed properties, we define the proxy getters on
// the Vue instances at extension time, on the extended prototype. This
// avoids Object.defineProperty calls for each instance created.
if (Sub.options.props) {
initProps(Sub)
}
if (Sub.options.computed) {
initComputed(Sub)
}
// allow further extension/mixin/plugin usage
Sub.extend = Super.extend
Sub.mixin = Super.mixin
Sub.use = Super.use
// create asset registers, so extended classes
// can have their private assets too.
ASSET_TYPES.forEach(function (type) {
Sub[type] = Super[type]
})
// enable recursive self-lookup
if (name) {
Sub.options.components[name] = Sub
}
// keep a reference to the super options at extension time.
// later at instantiation we can check if Super's options have
// been updated.
Sub.superOptions = Super.options
Sub.extendOptions = extendOptions
Sub.sealedOptions = extend({}, Sub.options)
// cache constructor
cachedCtors[SuperId] = Sub
return Sub
}
Vue.extend 函数总体是通过原型继承,创建 Vue 构造器的子类 Sub。
Vue.extend 函数开始有缓存策略,如果使用两个相同的对象创建 Sub,返回的结果是一样的。
const obj = {
template: `<div>extend</div>`,
data: function () {
return {
a: 1
}
}
};
let res = Vue.extend(obj);
let res1 = Vue.extend(obj);
console.log(res === res1) // true
res 和 res1 都是通过相同 obj 创建的,最后 res 和 res1 是同一个。
const Sub = function VueComponent (options) {
this._init(options)
}
Sub.prototype = Object.create(Super.prototype)
Sub.prototype.constructor = Sub
Ctor = resolveAsyncComponent(asyncFactory, baseCtor)
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
)
}
Vue 源码分析(组件)
组件注册
局部注册
局部注册比较简单。在组件内部使用 components 选择添加注册的组件即可。
局部注册的组件会在 Vue 构造函数合并选项时,将局部注册的组件添加到 vm.$options.components 上,所以只能本组件中使用。
全局注册
全局注册是通过 Vue.component(tagName, options) 注册的。Vue.component 是在 src/core/global-api/assets.js 文件中定义的
ASSET_TYPES 包括以下选项:
name 属性就取 name 或者 id 选项。
this.options._base 就是 Vue 构造函数。所以组件就是通过 Vue.extend 创建,最后添加到 Vue.options[components] 上,所以能全局访问。
Vue.extend
上一节我们知道全局组件是通过 Vue.extend 创建的,这里详细介绍这个函数,它是定义在 src/core/global-api/extend.js 文件中
Vue.extend 函数总体是通过原型继承,创建 Vue 构造器的子类 Sub。
Vue.extend 函数开始有缓存策略,如果使用两个相同的对象创建 Sub,返回的结果是一样的。
res 和 res1 都是通过相同 obj 创建的,最后 res 和 res1 是同一个。
这里就是继承了 Vue 构造函数。
接下来就是初始化 Sub, 添加各种属性和方法以及,这些方法和属性就是 Vue 的全局属性和方法。
异步组件
平时我们可能会用到异步组件
Vue.component 注册的不在是一个对象,而是一个函数。所以 Vue.component 函数不会执行 Vue.extend。但是在最后渲染的时候会调用 createComponent 函数,最后调用 resolveAsyncComponent 函数处理异步组件。
createComponent 函数会在组件渲染的时候说明。
resolveAsyncComponent 函数定义在 src/core/vdom/helpersresolve-async-component.js 文件中
resolveAsyncComponent 函数有两个参数:asyncFactory 就是异步函数,baseCtor 是 Vue 构造函数。根据 Vue 官方文档,异步组件有三种形式:
asyncFactory 是
asyncFactory 返回一个 Promise
有加载状态的异步组件
其中 component 属性要求返回一个 Promise 对象。
异步组件从加载到最后渲染出来,resolveAsyncComponent 会执行两次。
第一次执行 resolveAsyncComponent 函数,返回值为 undefined 或者 AsyncComponent.loading。只有存在 loading 属性,并且 delay 为 0 的情况才返回 loading 值。如果返回值为 undefined,会通过 createAsyncPlaceholder 函数创建一个注释节点作为占位符。
当异步组件获取成功时,会通过 forceRender 函数调用 $forceUpdate 更新组件,在更新组件的过程中,第二次调用 createAsyncPlaceholder 函数,此时 asyncFactory 函数的 error 或者 resolved 存在值。
会进入其中一个 if 。
在 createAsyncPlaceholder 函数中有 owner 变量。
一个异步组件可能有多个组件使用,owner 代表当前组件。如果有两个以上组件使用,会使用 factory.owners 数组将相关组件存起来。
这段代码避免二次执行异步组件。
createElement 函数的第一个参数也可以是一个 async 函数,最终也会进入 resolveAsyncComponent 函数中。
The text was updated successfully, but these errors were encountered: