1. Construtor Vue
No primeiro capítulo deste artigo, veremos
Vue
a definição do construtor no código-fonte.
(um)src/platforms/runtime-with-compiler.ts
Os códigos no platforms
diretório são todos códigos relacionados à plataforma. Como mencionamos no artigo anterior, no arquivo os métodos runtime-with-compiler.ts
são definidos e convertidos em funções. Os códigos-chave neste arquivo são:$mount
html
render
import Vue from './runtime/index'
const mount = Vue.prototype.$mount
// 重写$mount方法
Vue.prototype.$mount = xx;
// 给vue添加compile方法,将html字符串转换成render函数
Vue.compile = compileToFunctions
export default Vue as GlobalAPI
Este arquivo é import
importado Vue
, o caminho absoluto do arquivo src/platforms/web/runtime/index.ts
:,
(dois)src/platforms/web/runtime/index.ts
Vamos verificar este arquivo. Aqui estão algumas linhas principais de código:
import Vue from 'core/index'
// 注册平台相关的指令和组件
// extend:将参数二扩展到参数一上
extend(Vue.options.directives, platformDirectives)
// Vue.options.components存储全局组件
extend(Vue.options.components, platformComponents)
// 给Vue原型上添加$mount方法
Vue.prototype.$mount = function (
el?: string | Element,
hydrating?: boolean
): Component {
el = el && inBrowser ? query(el) : undefined
return mountComponent(this, el, hydrating)
}
export default Vue
Este arquivo é usado principalmente para registrar instruções e componentes exclusivos para a plataforma e definir Vue
métodos . Seu Vue também é importado do mundo externo. Vamos conferir emprototype
$mount
core/index
(três)src/core/index.ts
Aqui estão algumas linhas principais de código:
import Vue from './instance/index'
import {
initGlobalAPI } from './global-api/index'
// 初始化Vue的静态成员
initGlobalAPI(Vue)
// 给Vue.prototype添加属性
Object.defineProperty(Vue.prototype, '$isServer', {
get: isServerRendering
})
export default Vue
Este método é usado para inicializar Vue
os membros estáticos da instância e adicionar Vue.prototype
diversas propriedades relacionadas ao ambiente em execução. Mas Vue
também é introduzido de fora. Olhamos ./instance/index
para Vue em
(Quatro)src/core/instance/index.ts
Aqui finalmente vemos Vue
o construtor
function Vue(options) {
if (__DEV__ && !(this instanceof Vue)) {
warn('Vue is a constructor and should be called with the `new` keyword')
}
// 调用_init方法
this._init(options)
}
// 给Vue初始化init方法
initMixin(Vue)
// 注册vm 的 $data/$props/$set/$delete/$watch
stateMixin(Vue)
// 初始化事件相关方法
eventsMixin(Vue)
// 初始化生命周期相关的混入方法
lifecycleMixin(Vue)
//@ts-expect-error Vue has function type
// 混入render方法
renderMixin(Vue)
O objetivo deste arquivo é definir Vue
o construtor e Vue
combinar membros de instância comuns.
2. Membros estáticos do Vue
Neste capítulo, apresentaremos Vue
a definição de membros estáticos. Os membros estáticos do Vue são definidos principalmente em métodos src/core/global-api/index.ts
de arquivo e suas funções são mostradas na figura abaixo: Código-fonte:initGlobalAPI()
initGlobalAPI()
initGlobalAPI()
export function initGlobalAPI(Vue: GlobalAPI) {
// config
const configDef: Record<string, any> = {
}
configDef.get = () => config
// 非生产环境下,不允许调用config的set方法修改Vue.config
if (__DEV__) {
configDef.set = () => {
warn(
'Do not replace the Vue.config object, set individual fields instead.'
)
}
}
// 初始化Vue.config静态属性
Object.defineProperty(Vue, 'config', configDef)
// Vue内部使用的方法,不建议外部使用
Vue.util = {
warn,
extend,
mergeOptions,
defineReactive
}
// 静态方法
Vue.set = set
Vue.delete = del
Vue.nextTick = nextTick
// 2.6 explicit observable API
// 设置响应式数据
Vue.observable = <T>(obj: T): T => {
observe(obj)
return obj
}
// 初始化Vue.options静态属性,并给其扩展
// 初始化Vue.options.components、Vue.options.directives、Vue.options.filters
// 存储全局组件、指令、过滤器
Vue.options = Object.create(null)
ASSET_TYPES.forEach(type => {
Vue.options[type + 's'] = Object.create(null)
})
// 记录当前Vue构造函数
Vue.options._base = Vue
// 把builtInComponents对象属性拷贝到Vue.options.components中
// 注册全局组件keep-alive
extend(Vue.options.components, builtInComponents)
// 初始化Vue.use静态方法,用来注册插件
initUse(Vue)
// 初始化Vue.mixin静态方法,实现混入
initMixin(Vue)
// 初始化Vue.extend静态方法,基于传入的options返回一个组件的构造函数
initExtend(Vue)
// 初始化Vue.component、Vue.directive、Vue.filter静态方法
initAssetRegisters(Vue)
}
initUse(Vue)
export function initUse(Vue: GlobalAPI) {
// Vue.use方法
// plugin:要注册的插件
Vue.use = function (plugin: Function | any) {
// this指向Vue构造函数
const installedPlugins =
this._installedPlugins || (this._installedPlugins = [])
if (installedPlugins.indexOf(plugin) > -1) {
// 已经注册过了,直接返回
return this
}
// 注册插件就是调用插件
// 如果插件是一个对象,那么调用其install方法
// 如果插件是一个函数,那么直接调用
// arguments是调用Vue.use时传入的参数,第一个参数一定是插件,
// 后面的参数是传给插件的参数
const args = toArray(arguments, 1)
// 把Vue构造函数添加到参数的第一个位置
args.unshift(this)
if (isFunction(plugin.install)) {
// apply将数组展开成一个个参数
plugin.install.apply(plugin, args)
} else if (isFunction(plugin)) {
plugin.apply(null, args)
}
// 把插件添加到已注册插件列表中
installedPlugins.push(plugin)
return this
}
}
initMixin(Vue)
export function initMixin(Vue: GlobalAPI) {
Vue.mixin = function (mixin: Object) {
// 把传过来的选项传到Vue.options中
// 注册全局选项
this.options = mergeOptions(this.options, mixin)
return this
}
}
initExtend(Vue)
export function initExtend(Vue: GlobalAPI) {
// 每个实例构造器,包括Vue,都有一个唯一的cid,便于缓存和创建子构造函数
Vue.cid = 0
let cid = 1
// 给Vue添加extend方法
Vue.extend = function (extendOptions: any): typeof Component {
extendOptions = extendOptions || {
}
const Super = this
const SuperId = Super.cid
const cachedCtors = extendOptions._Ctor || (extendOptions._Ctor = {
})
if (cachedCtors[SuperId]) {
return cachedCtors[SuperId]
}
const name =
getComponentName(extendOptions) || getComponentName(Super.options)
if (__DEV__ && name) {
validateComponentName(name)
}
// 创建组件构造函数
const Sub = function VueComponent(this: any, options: any) {
this._init(options)
} as unknown as typeof Component
// 继承Vue
Sub.prototype = Object.create(Super.prototype)
Sub.prototype.constructor = Sub
Sub.cid = cid++
// 合并选项
Sub.options = mergeOptions(Super.options, extendOptions)
Sub['super'] = Super
// 对于props,定义到Sub.prototype._props上
if (Sub.options.props) {
initProps(Sub)
}
// computed定义到Sub.prototype上
if (Sub.options.computed) {
initComputed(Sub)
}
// 初始化extension/mixin/plugin
Sub.extend = Super.extend
Sub.mixin = Super.mixin
Sub.use = Super.use
// 初始化component()、directive()、filter()
ASSET_TYPES.forEach(function (type) {
Sub[type] = Super[type]
})
// 如果传进来的选项有name属性,将构造函数存储到options中
if (name) {
Sub.options.components[name] = Sub
}
//存储父类的options选项
Sub.superOptions = Super.options
// 传进来的选项
Sub.extendOptions = extendOptions
Sub.sealedOptions = extend({
}, Sub.options)
// 缓存 constructor
cachedCtors[SuperId] = Sub
// 返回组件构造函数
return Sub
}
}
initAssetRegisters(Vue)
export function initAssetRegisters(Vue: GlobalAPI) {
// ASSET_TYPES:['component', 'directive', 'filter]
// 这几个方法使用的时候都是Vue.component('xxx', definition)
// definition: Function | Object
// 如果没有传definition,那么就是获取全局组件、指令、过滤器
ASSET_TYPES.forEach(type => {
Vue[type] = function (
id: string,
definition?: Function | Object
): Function | Object | void {
if (!definition) {
// 如果没有第二个参数,获取对应id组件、指令、过滤器
return this.options[type + 's'][id]
} else {
if (__DEV__ && type === 'component') {
validateComponentName(id)
}
// isPlainObject:判断是否是纯对象,区分于函数、数组、null、Date、RegExp等
if (type === 'component' && isPlainObject(definition)) {
// 给组件定义name属性,如果没有name属性,就使用id
definition.name = definition.name || id
// this.options._base:Vue构造函数
// Vue.extend:根据传入的选项,返回一个组件的构造函数
// 所以这里的definition是一个组件的构造函数
definition = this.options._base.extend(definition)
}
if (type === 'directive' && isFunction(definition)) {
definition = {
bind: definition, update: definition }
}
// 给组件、指令、过滤器添加到Vue.options中
// 直接传递Vue.extend()构造函数会直接将构造函数存储到options中
this.options[type + 's'][id] = definition
return definition
}
}
})
}
3. Membros da instância Vue
src/core/instance/init.ts
Vue
Os membros da instância definidos no arquivo são Vue.prototype
membros adicionados. Vue
O objeto da instância pode ser herdado por meio da cadeia de protótipo. Os membros da instância são inicializados no arquivo por meio dos seguintes blocos de função:
// 给Vue的实例对象上增加init方法
initMixin(Vue)
// 注册vm 的 $data/$props/$set/$delete/$watch
stateMixin(Vue)
// 初始化vm中事件相关方法
eventsMixin(Vue)
// 初始化生命周期相关的混入方法
// _update/$forceUpdate/$destroy
// _update中调用了__patch__方法对比差异更新DOM
lifecycleMixin(Vue)
// 混入render方法
renderMixin(Vue)
As principais funções implementadas são mostradas na figura abaixo: um método é adicionado à
instância , que é o método de inicialização da instância, este método será executado no construtor. Vejamos as funções específicas do método:initMixin(Vue)
Vue
_init()
Vue
Vue
_init()
4. Depurando o processo de inicialização do Vue
Vue
Vue
O processo de inicialização é realizado principalmente nos quatro arquivos do Capítulo 1. A inicialização dos membros da instância e a inicialização dos métodos estáticos são concluídas . Ao desconectar a depuração, o processo geral de execução é o seguinte:
5. Depurando o primeiro processo de renderização
Vue.proptotype._init()
No mapa mental desenhado no Capítulo 3 acima , a última parte desta função é vm.$mount()
o método. O primeiro processo de renderização começa a partir desta função.
6. Extensão
1. Habilidades de depuração: Clique no pequeno + na barra de observação do navegador Chrome e insira os dados que deseja visualizar. Você sempre pode visualizar as alterações nos dados durante a depuração do ponto de interrupção.