官方实现
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/lifecycle.ts lifecycleMixin()
export function lifecycleMixin(Vue: typeof Component) {
/**
* 负责更新页面,页面首次渲染和后续更新的入口位置,也是 patch 的入口位置
*/
Vue.prototype._update = function (vnode: VNode, hydrating?: boolean) {
const vm: Component = this
const prevEl = vm.$el
const prevVnode = vm._vnode
const restoreActiveInstance = setActiveInstance(vm)
vm._vnode = vnode
// Vue.prototype.__patch__ is injected in entry points
// based on the rendering backend used.
if (!prevVnode) {
// 首次渲染,即初始化页面时走这里
vm.$el = vm.__patch__(vm.$el, vnode, hydrating, false /* removeOnly */)
} else {
// 响应式数据更新时,即更新页面时走这里
vm.$el = vm.__patch__(prevVnode, vnode)
}
restoreActiveInstance()
// update __vue__ reference
if (prevEl) {
prevEl.__vue__ = null
}
if (vm.$el) {
vm.$el.__vue__ = vm
}
// if parent is an HOC, update its $el as well
let wrapper: Component | undefined = vm
while (
wrapper &&
wrapper.$vnode &&
wrapper.$parent &&
wrapper.$vnode === wrapper.$parent._vnode
) {
wrapper.$parent.$el = wrapper.$el
wrapper = wrapper.$parent
}
// updated hook is called by the scheduler to ensure that children are
// updated in a parent's updated hook.
}
/**
* 直接调用 watcher.update 方法,迫使组件重新渲染。
* 它仅仅影响实例本身和插入插槽内容的子组件,而不是所有子组件
*/
Vue.prototype.$forceUpdate = function () {
const vm: Component = this
if (vm._watcher) {
vm._watcher.update()
}
}
/**
* 完全销毁一个实例。清理它与其它实例的连接,解绑它的全部指令及事件监听器。
*/
Vue.prototype.$destroy = function () {
const vm: Component = this
if (vm._isBeingDestroyed) {
// 表示实例已经销毁
return
}
// 调用 beforeDestroy 钩子
callHook(vm, 'beforeDestroy')
// 标识实例已经销毁
vm._isBeingDestroyed = true
// 把自己从老爹($parent)的肚子里($children)移除
const parent = vm.$parent
// 移除依赖监听
if (parent && !parent._isBeingDestroyed && !vm.$options.abstract) {
remove(parent.$children, vm)
}
// teardown scope. this includes both the render watcher and other
// watchers created
vm._scope.stop()
// remove reference from data ob
// frozen object may not have observer.
if (vm._data.__ob__) {
vm._data.__ob__.vmCount--
}
// call the last hook...
vm._isDestroyed = true
// 调用 __patch__,销毁节点
vm.__patch__(vm._vnode, null)
// 调用 destroyed 钩子
callHook(vm, 'destroyed')
// 关闭实例的所有事件监听
vm.$off()
// remove __vue__ reference
if (vm.$el) {
vm.$el.__vue__ = null
}
// release circular reference (#6759)
if (vm.$vnode) {
vm.$vnode.parent = null
}
}
}