前言
初步读完vue(v2.6.10)
的源码,现将读后感记录如下,故事就是由此开始。
小提示:配合源码食用更佳美味。
混沌初开
开始的开始,vue就是一个简单的函数。
src/core/instance/index.js
function Vue (options) {
this._init(options)
}
扩展功能
设计模式之混入模式,对Vue进行扩展,很值得学习的一种方式。
initMixin()
定义了_init方法,是入口函数,在new Vue()时第一时间执行的方法。
src/core/instance/init.js
Vue.prototype._init = function (options?: Object){}
stateMixin()
数据相关的扩展。
src/core/instance/state.js
$data & $props
Vue
实例观察的数据对象和当前组件接收到的props
对象。
实际上是代理到_data
和_props
Object.defineProperty(Vue.prototype, '$data', {
get(){
return this._data
}
})
Object.defineProperty(Vue.prototype, '$props', {
get(){
return this._props
}
})
$set & $delete
是 Vue.set
和Vue.delete
的别名
Vue.prototype.$set = set
Vue.prototype.$delete = del
$watch
实现了$watch
方法,观察Vue
实例变化的一个表达式或计算属性函数。
Vue.prototype.$watch = function () {}
eventsMixin()
事件相关的扩展
src/core/instance/events.js
$on
监听当前实例上的自定义事件。
Vue.prototype.$on = function (event: string | Array<string>, fn: Function): Component{}
$once
监听一个自定义事件,但是只触发一次。一旦触发之后,监听器就会被移除。
Vue.prototype.$once = function (event: string, fn: Function): Component{}
$off
移除自定义事件监听器。
Vue.prototype.$off = function (event?: string | Array<string>, fn?: Function): Component{}
$emit
触发当前实例上的事件。
Vue.prototype.$emit = function (event: string): Component {}
lifecycleMixin()
生命周期相关的扩展
src/core/instance/lifecycle.js
_update
私有方法,更新dom节点流程的重要函数
Vue.prototype._update = function (vnode: VNode, hydrating?: boolean) {}
$forceUpdate
迫使 Vue 实例重新渲染。简单粗暴
Vue.prototype.$forceUpdate = function (){ // 触发更新}
$destroy
完全销毁一个实例。
Vue.prototype.$destroy = function (){ // 移除事件 指令等 }
installRenderHelpers
render相关的扩展
src/core/instance/render.js
installRenderHelpers
定义render函数有关的方法,在执行render时使用
src/core/instance/render-helpers/index.js
export function installRenderHelpers (target: any) {
target._o = markOnce
target._n = toNumber
target._s = toString
target._l = renderList
target._t = renderSlot
target._q = looseEqual
target._i = looseIndexOf
target._m = renderStatic
target._f = resolveFilter
target._k = checkKeyCodes
target._b = bindObjectProps
target._v = createTextVNode
target._e = createEmptyVNode
target._u = resolveScopedSlots
target._g = bindObjectListeners
target._d = bindDynamicKeys
target._p = prependModifier
}
$nextTick
将回调延迟到下次 DOM 更新循环之后执行。跟Vue.nextTick
一样,但是绑定了实例的this
Vue.prototype.$nextTick = function (fn: Function) {
return nextTick(fn, this)
}
_render
私有方法,创建vnode流程的重要函数
Vue.prototype._render = function (): VNode{}
核心代码
src/core/index.js
initGlobalAPI()
全局api
src/core/global-api/index.js
config
vue 全局配置 代理到vue的config,在new Vue()之前可以修改
全局配置 src/core/config.js
import config from '../config'
Object.defineProperty(Vue, 'config', {
get() {
return config
}
})
util
vue的工具函数
Vue.util = {
warn,
extend,
mergeOptions,
defineReactive
}
常用方法
Vue.set = set // 向响应式对象中添加一个属性
Vue.delete = del // 删除对象的属性。
Vue.nextTick = nextTick // 在下次 DOM 更新循环结束之后执行延迟回调。
observable
让一个对象可响应。
Vue.observable = <T>(obj: T): T => {
observe(obj)
return obj
}
options
默认的options
Vue.options = Object.create(null)
组件、指令、过滤器的存放属性
组件、指令、过滤器实际上就是在options中创建了三个属性。
ASSET_TYPES.forEach(type => {
Vue.options[type + 's'] = Object.create(null)
})
// Vue.options.components
// Vue.options.directives
// Vue.options.filters
options._base
私有属性,缓存Vue
Vue.options._base = Vue
内部组件
定义了内部组件KeepAlive
extend(Vue.options.components, builtInComponents)
initUse(Vue)
定义了Vue.use方法, 安装 Vue.js 插件。
src/core/global-api/use.js
Vue.use = function (plugin: Function | Object) {}
initMixin(Vue)
定义了Vue.mixin方法, 全局注册一个混入
src/core/global-api/mixin.js
Vue.mixin = function (mixin: Object) {}
initExtend(Vue)
定义了Vue.extend方法, Vue 构造器,创建一个“子类”。
src/core/global-api/extend.js
Vue.extend = function (extendOptions: Object): Function
initAssetRegisters(Vue)
用于实现组件、指令、过滤器方法
Vue.directive 注册或获取全局指令。
Vue.filter 注册或获取全局过滤器。
Vue.component 注册或获取全局组件。
src/core/global-api/assets.js
ASSET_TYPES.forEach(type => {
Vue[type] = function (
id: string,
definition: Function | Object
): Function | Object | void {
if (!definition) {
return this.options[type + 's'][id]
} else {
if (type === 'component' && isPlainObject(definition)) {
definition.name = definition.name || id
definition = this.options._base.extend(definition)
}
if (type === 'directive' && typeof definition === 'function') {
definition = { bind: definition, update: definition }
}
this.options[type + 's'][id] = definition
return definition
}
}
})
version
版本号
Vue.version = '__VERSION__'
web运行时
再次之上是vue的核心代码,与平台无关。以下是web平台有关代码。
我们通常用cli
写的代码是不需要编译器的,因为vue-loader有一个编译过程,这个版本通常较小,但是不带编译器。
仅运行时的版本
src/platforms/web/entry-runtime.js
实际上就是src/platforms/web/runtime/index.js
定义配置
Vue.config.mustUseProp = mustUseProp
Vue.config.isReservedTag = isReservedTag
Vue.config.isReservedAttr = isReservedAttr
Vue.config.getTagNamespace = getTagNamespace
Vue.config.isUnknownElement = isUnknownElement
内部指令
平台相关 定义内部指令v-model
和v-show
extend(Vue.options.directives, platformDirectives)
内部组件
平台相关 定义内部组件Transition
和TransitionGroup
,上面提到过平台无关的内部组件KeepAlive
extend(Vue.options.components, platformComponents)
patch
打补丁方法,平台不一样打补丁的方法也不一样,设计很巧妙。
Vue.prototype.__patch__ = inBrowser ? patch : noop
$mount
如果 Vue 实例在实例化时没有收到 el 选项,则它处于“未挂载”状态,没有关联的 DOM 元素。可以使用 vm.$mount()
手动地挂载一个未挂载的实例。
最后执行了其实是src/core/instance/lifecycle.js
中的mountComponent
方法。也就是对mountComponent
的一次封装
Vue.prototype.$mount = function (
el?: string | Element,
hydrating?: boolean
): Component {
el = el && inBrowser ? query(el) : undefined
return mountComponent(this, el, hydrating)
}
带编译的运行时
这个版本比较大,因为带有编译器。
src/platforms/web/entry-runtime-with-compiler.js
$mount 二次封装
const mount = Vue.prototype.$mount
Vue.prototype.$mount = function (
el?: string | Element,
hydrating?: boolean
): Component {
el = el && query(el)
const options = this.$options
// 其实所谓的编译就是讲模板编译成render函数
// 存在render将直接使用render函数,则不需要编译
// 不存在render则读取template template有害几种配置方法也是在此处处理
if (template) {
const { render, staticRenderFns } = compileToFunctions(template, {
outputSourceRange: process.env.NODE_ENV !== 'production',
shouldDecodeNewlines,
shouldDecodeNewlinesForHref,
delimiters: options.delimiters,
comments: options.comments
}, this)
options.render = render
options.staticRenderFns = staticRenderFns
}
// 实际还是调用了$mount
return mount.call(this, el, hydrating)
}
compile
在 render 函数中编译模板字符串 编译器版本特有。
Vue.compile = compileToFunctions
系列
- 【源码导读 】在new Vue()之前,Vue是什么样子的?(本文)
- 【源码解析】创建Vue实例时干了什么?
- 【源码分析】Vue的响应数据
- 【敬请期待】...
结尾
感谢各位的阅读,错误是在所难免的,若有错误,或者有更好的理解,请在评论区留言,再次感谢。希望大家相互学习,共同进步。