前言
vue2的生命周期采用Vue.Mixin()
去全局混入,然后在使用订阅发布
的模式去调用生命周期
以数组的形式去订阅 格式:{created:[a(),b(),c()],....}
src目录改动新增代码目录:
- index.js
- global-api // 混入
- index.js
- utils
- index.js // 实现订阅生命周期
- lifeCycle.js // 生命周期的调用
- init.js // 订阅生命周期 及调用
Vue全局混入代码global-api/index.js
import { mergeOptions } from "../utils/index"
export function initGlobApi(Vue) {
Vue.options = {}
Vue.Mixin = function (mixin) {
// 对象的合并
this.options = mergeOptions(this.options, mixin)
console.log(this.options);
// console.log(Vue);
}
}
以数组的形式去订阅生命周期 utils/index.js
生成的格式 {created:[a(),b(),c()],....}
export const HOOKS = [
"beforeCreate",
"created",
"beforeMount",
"mounted",
"beforeUpdate",
"updated",
"beforeDestroy",
"destroyed",
]
// 策略模式
let starts = {}
starts.data = function (parenVal, childVal) {
return childVal
}
starts.computed = function () { }
starts.watch = function () { }
starts.methods = function () { }
HOOKS.forEach(hooks => {
starts[hooks] = mergeHook
})
function mergeHook(parentVal,childVal) {
if (childVal) {
if (parentVal) {
return parentVal.concat(childVal)
} else {
return [childVal]
}
} else {
return [parentVal]
}
}
// 订阅生命周期
export function mergeOptions(parent, child) {
const options = {}
for (let key in parent) {
mergeField(key)
}
for (let key in child) {
mergeField(key)
}
function mergeField(key) {
// 根据key 策略模式
if (starts[key]) {
options[key] = starts[key](parent[key], child[key])
} else {
options[key] = child[key]
}
}
return options
}
根目录index.js
import { initMixin } from "./init"
import { lifeCycleMixin } from "./lifeCycle";
import { renderMixin } from "./vnode/index";
import { initGlobApi } from "./global-api/index";
/**
* @author xwya
* @since 2023-12-11
* @description Vue 构造函数
* @param {Object} options - Vue 的初始化选项。
* @returns {void} - 没有返回值。
*/
function Vue(options) {
// 初始化
this._init(options);
}
initMixin(Vue)
lifeCycleMixin(Vue) // 添加生命周期
renderMixin(Vue) // 添加_render
// 调用向实例上添加混入
initGlobApi(Vue)
export default Vue;
init.js文件
import { initState } from "./initState";
import { compileToFunction } from "./compile/index";
import { mounetComponent,callHook } from "./lifeCycle";
import { mergeOptions } from "./utils/index";
/**
* @description 初始化vue
* @param {Object} Vue
* @returns {void}
*/
export function initMixin(Vue) {
Vue.prototype._init = function (options) {
let vm = this
vm.$options = mergeOptions(Vue.options, options) // 订阅生命周期
callHook(vm, 'beforeCreate')
// 初始化状态
initState(vm)
callHook(vm, 'created')
// 渲染模板
if (vm.$options.el) {
vm.$mount(vm.$options.el)
}
}
// 创建$mount 进行模板编译
Vue.prototype.$mount = function (el) {
let vm = this
// 获取dom元素
el = document.querySelector(el)
vm.$el= el
let options = vm.$options
// 没有render函数
if (!options.render) {
let template = options.template
if (!template && el) {
// 获取html
el = el.outerHTML
// 转换成ast语法树 vnode(虚拟dom) [ast语法树是能操作js和css 虚拟dom只能操作一个节点]
let render = compileToFunction(el)
// render函数
options.render = render
}
}
// 执行生成模板
mounetComponent(vm, el)
}
}
lifeCycle.js 文件
import { patch } from "./vnode/patch";
export function mounetComponent(vm, el) {
// 页面加载前生命周期
callHook(vm, 'beforeMounted')
// (1) vm._render 将render转换成虚拟dom (vnode)
// (2) vm._update 将vnode变成真实dom在放到页面上
vm._updata(vm._render())
callHook(vm, 'mounted')
}
export function lifeCycleMixin(Vue) {
Vue.prototype._updata = function (vnode) {
let vm = this
// 传两个参数 旧的dom 和 vnode
vm.$el= patch(vm.$el, vnode)
}
}
// 调用生命周期方法
export function callHook(vm, hook) {
const handlers = vm.$options[hook]
if (handlers) {
handlers.forEach(handler => {
handler.call(this)
})
}
}