跳到主要内容

官方实现

2023年06月11日
柏拉文
越努力,越幸运

一、src/core/instance/index.ts


import { initMixin } from './init'
import { stateMixin } from './state'
import { renderMixin } from './render'
import { eventsMixin } from './events'
import { lifecycleMixin } from './lifecycle'
import { warn } from '../util/index'
import type { GlobalAPI } from 'types/global-api'

function Vue(options) {
if (__DEV__ && !(this instanceof Vue)) {
warn('Vue is a constructor and should be called with the `new` keyword')
}

// 调用 Vue.prototype._init 方法,该方法是在 initMixin 中定义的
this._init(options)
}

// 定义 Vue.prototype._init 方法
initMixin(Vue)
/**
* 定义:
* Vue.prototype.$data
* Vue.prototype.$props
* Vue.prototype.$set
* Vue.prototype.$delete
* Vue.prototype.$watch
*/
stateMixin(Vue)
/**
* 定义 事件相关的 方法:
* Vue.prototype.$on
* Vue.prototype.$once
* Vue.prototype.$off
* Vue.prototype.$emit
*/
eventsMixin(Vue)
/**
* 定义:
* Vue.prototype._update
* Vue.prototype.$forceUpdate
* Vue.prototype.$destroy
*/
lifecycleMixin(Vue)
/**
* 执行 installRenderHelpers,在 Vue.prototype 对象上安装运行时便利程序
*
* 定义:
* Vue.prototype.$nextTick
* Vue.prototype._render
*/
renderMixin(Vue)

export default Vue as unknown as GlobalAPI

二、src/core/instance/state.ts stateMixin()


export function stateMixin(Vue: typeof Component) {
// data
const dataDef: any = {}
dataDef.get = function () {
return this._data
}
// props
const propsDef: any = {}
propsDef.get = function () {
return this._props
}
if (__DEV__) {
dataDef.set = function () {
warn(
'Avoid replacing instance root $data. ' +
'Use nested data properties instead.',
this
)
}
propsDef.set = function () {
warn(`$props is readonly.`, this)
}
}
// 将 data 属性和 props 属性挂载到 Vue.prototype 对象上
// 这样在程序中就可以通过 this.$data 和 this.$props 来访问 data 和 props 对象了
Object.defineProperty(Vue.prototype, '$data', dataDef)
Object.defineProperty(Vue.prototype, '$props', propsDef)

Vue.prototype.$set = set
Vue.prototype.$delete = del

Vue.prototype.$watch = function (
expOrFn: string | (() => any),
cb: any,
options?: Record<string, any>
): 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)
if (options.immediate) {
const info = `callback for immediate watcher "${watcher.expression}"`
pushTarget()
invokeWithErrorHandling(cb, vm, [watcher.value], vm, info)
popTarget()
}
return function unwatchFn() {
watcher.teardown()
}
}
}

三、src/core/instance/state.ts $watch()


/**
* 创建 watcher,返回 unwatch,共完成如下 5 件事:
* 1、兼容性处理,保证最后 new Watcher 时的 cb 为函数
* 2、标示用户 watcher
* 3、创建 watcher 实例
* 4、如果设置了 immediate,则立即执行一次 cb
* 5、返回 unwatch
* @param {*} expOrFn key
* @param {*} cb 回调函数
* @param {*} options 配置项,用户直接调用 this.$watch 时可能会传递一个 配置项
* @returns 返回 unwatch 函数,用于取消 watch 监听
*/


Vue.prototype.$watch = function (
expOrFn: string | (() => any),
cb: any,
options?: Record<string, any>
): Function {
const vm: Component = this
// 兼容性处理,因为用户调用 vm.$watch 时设置的 cb 可能是对象
if (isPlainObject(cb)) {
return createWatcher(vm, expOrFn, cb, options)
}
// options.user 表示用户 watcher,还有渲染 watcher,即 updateComponent 方法中实例化的 watcher
options = options || {}
options.user = true
// 创建 watcher
const watcher = new Watcher(vm, expOrFn, cb, options)
// 如果用户设置了 immediate 为 true,则立即执行一次回调函数
if (options.immediate) {
const info = `callback for immediate watcher "${watcher.expression}"`
pushTarget()
invokeWithErrorHandling(cb, vm, [watcher.value], vm, info)
popTarget()
}
// 返回一个 unwatch 函数,用于解除监听
return function unwatchFn() {
watcher.teardown()
}
}