1. vue 目录结构 (src)
|-- dist 打包后的vue版本
|-- flow 类型检测,3.0换了typeScript // 使用flow定义和检测类型,增强代码健壮性
|-- script 构建不同版本vue的相关配置
|-- src 源码
|-- compiler 编译器 // 将template编译成render函数
|-- core 不区分平台的核心代码
|-- components 通用的抽象组件
|-- global-api 全局API
|-- instance 实例的构造函数和原型方法
|-- observer 数据响应式 // vue检测数据变化并更新视图的实现
|-- util 常用的工具方法
|-- vdom 虚拟dom相关 // 将render函数转为vnode从而patch为真实dom以及diff算法的代码实现
|-- platforms 不同平台不同实现
|-- server 服务端渲染
|-- sfc .vue单文件组件解析
|-- shared 全局通用工具方法
|-- test 测试
和运行时版本的关键所在,完整版就自带这个编译器,而运行时版本就没有,
(面试题) 请问 runtime compiler 和 runtime-only 这两个版本的区别?
文件大小的区别,带编译的版本要比不带的版本文件要大6kb左右
编译时机不同:编译运行时版本会在运行时进行编译,性能会有一定损耗;运行时版本借助于 vue-loader 做的离线编译,运行速度更快。
2. vue入口 首先是构造函数 core/instance/index.js
function Vue (options) {
if (process.env.NODE_ENV !== 'production' &&
!(this instanceof Vue)
) {
warn('Vue is a constructor and should be called with the `new` keyword')
}
this._init(options)
}
initMixin(Vue):定义_init方法。
stateMixin(Vue):定义数据相关的方法$set,$delete,$watch方法。
eventsMixin(Vue):定义事件相关的方法$on,$once,$off,$emit。
lifecycleMixin(Vue):定义_update,及生命周期相关的$forceUpdate和$destroy。
renderMixin(Vue):定义$nextTick,_render将render函数转为vnode。
这些初始化后还会定义一些全局的API,initGlobalAPI(),里面包括
initUse(Vue) // Vue.use() initMixin(Vue) // Vue.mixins() initExtend(Vue) // Vue.extends() initAssetRegisters(Vue) // Vue.component,Vue.directive,Vue.filter方法
this._init(options) 是 core/instance/init.js中的挂载到vue的proptype原型链上的。
此处的options是传进来的Vue实例,eg:
new Vue(
{
el: '#app',
data: {
message: 'hello world'
},
components: {}
}
)
Vue.prototype._init = function (options?: Object) {
// 如果options里没有传components就开始解析构造器,传了就初始化这个组件
if (options && options._isComponent) {
// optimize internal component instantiation
// since dynamic options merging is pretty slow, and none of the
// internal component options needs special treatment.
initInternalComponent(vm, options)
} else {
vm.$options = mergeOptions(
resolveConstructorOptions(vm.constructor),
options || {},
vm
)
}}
initLifecycle(vm)
initEvents(vm)
initRender(vm)
callHook(vm, 'beforeCreate')
initInjections(vm) // resolve injections before data/props
initState(vm)
initProvide(vm) // resolve provide after data/props
callHook(vm, 'created')
所以在beforeCreate生命周期前vue 初始化了生命周期、事件处理机制
在created之前vue 初始化事件通信、options相关的
vue/src/core/instance/index.js stateMixin(Vue)
state.js
function initData (vm: Component) {
let data = vm.$options.data
data = vm._data = typeof data === 'function'
? getData(data, vm)
: data || {}
if (!isPlainObject(data)) {
data = {}
process.env.NODE_ENV !== 'production' && warn(
'data functions should return an object:\n' +
'https://vuejs.org/v2/guide/components.html#data-Must-Be-a-Function',
vm
)
}
// 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--) {
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 "${key}" is already declared as a prop. ` +
`Use prop default value instead.`,
vm
)
} else if (!isReserved(key)) {
proxy(vm, `_data`, key)
}
}
// observe data
observe(data, true /* asRootData */)
}
这是初始化data函数的方法,其中将props和methods中的对象和函数与data中的比较,避免重复。这里只在data里传了一个message字段,走到until/lang.js isReserved()
export function isReserved (str: string): boolean {
const c = (str + '').charCodeAt(0)
return c === 0x24 || c === 0x5F
}
0x24和0x5F是$和_对应的ASCII码值,isReserved函数是判断data里的字段是否带有$和_,为true会走到 proxy(vm, `_data`, key)这里,这里使用了代理模式
export function proxy (target: Object, sourceKey: string, key: string) {
sharedPropertyDefinition.get = function proxyGetter () {
return this[sourceKey][key]
}
sharedPropertyDefinition.set = function proxySetter (val) {
this[sourceKey][key] = val
}
Object.defineProperty(target, key, sharedPropertyDefinition)
}
这里是Object.defineProperty的实现,set和get, 然后实现observe(data, true /* asRootData */)
../observer/index.js
xport function observe (value: any, asRootData: ?boolean): Observer | void {
if (!isObject(value) || value instanceof VNode) {
return
}
let ob: Observer | void
if (hasOwn(value, '__ob__') && value.__ob__ instanceof Observer) {
ob = value.__ob__
} else if (
shouldObserve &&
!isServerRendering() &&
(Array.isArray(value) || isPlainObject(value)) &&
Object.isExtensible(value) &&
!value._isVue
) {
ob = new Observer(value)
}
if (asRootData && ob) {
ob.vmCount++
}
return ob
}
posted on
浙公网安备 33010602011771号