vue minxin实现、生命周期合并策略

定义全局 Mixin 函数

// src/global-api/mixin.js

import {mergeOptions} from '../util/index'

//初始化mixin方法,即往Vue上挂载minxin方法,核心是mergeOptions
export default function initMixin(Vue){ 
  Vue.mixin = function (mixin) {
    //   合并对象
      this.options=mergeOptions(this.options,mixin)
  };
}
};

进行初始化操作

// src/index.js
import { initMixin } from "./init.js";
// Vue就是一个构造函数 通过new关键字进行实例化
function Vue(options) {
  // 这里开始进行Vue初始化工作
  this._init(options);
}
// 此做法有利于代码分割
initMixin(Vue);
export default Vue;

mergeOptions

  • 对于钩子函数,Vue.mixin钩子会和Vue实例钩子进行合并(合并为一个数组,并且mixin的钩子排前,实例钩子排后);对于非钩子函数,Vue.mixin字段会被Vue实例字段替换掉(实例有这个字段就替换,没有就不替换);
// src/util/index.js
// 定义生命周期
export const LIFECYCLE_HOOKS = [
  "beforeCreate",
  "created",
  "beforeMount",
  "mounted",
  "beforeUpdate",
  "updated",
  "beforeDestroy",
  "destroyed",
];

// 合并策略
const strats = {};

//生命周期合并策略
function mergeHook(parentVal, childVal) {
  // 如果有儿子
  if (childVal) {
    if (parentVal) {
      // 合并成一个数组
      return parentVal.concat(childVal);
    } else {
      // 包装成一个数组
      return [childVal];
    }
  } else {
    return parentVal;
  }
}

// 为生命周期添加合并方法
LIFECYCLE_HOOKS.forEach((hook) => {
  strats[hook] = mergeHook;
});

// mixin核心方法,进行合并
export function mergeOptions(parent, child) {
  const options = {};
  // 先遍历父属性进行和子属性合并
  for (let k in parent) {
    mergeFiled(k);
  }
  // 遍历子属性中父属性没有的属性进行合并
  for (let k in child) {
    if (!parent.hasOwnProperty(k)) {
      mergeFiled(k);
    }
  }

  //真正合并字段方法
  function mergeFiled(k) {
  	//先判断是否是生命周期的属性
    if (strats[k]) {
      options[k] = strats[k](parent[k], child[k]);
    } else {
      // 非生命周期以外的合并
      options[k] = child[k] ? child[k] : parent[k];
    }
  }
  return options;
}

生命周期的调用

// src/lifecycle.js

export function callHook(vm, hook) {
  // 依次执行生命周期对应的方法
  const handlers = vm.$options[hook];
  //遍历对应的生命周期
  if (handlers) {
    for (let i = 0; i < handlers.length; i++) {
      handlers[i].call(vm); //生命周期里面的this指向当前实例
    }
  }
}

承接上文的this._init方法


export function initMixin (Vue: Class<Component>) {
	Vue.prototype._init = function (options) {
	  const vm = this;
	  // 这里的this代表调用_init方法的对象(实例对象)
	  //  this.$options就是用户new Vue的时候传入的属性和全局的Vue.options合并之后的结果
	
	  ...
	  
	  //vm.constructor=vm.prototype.constructor即指向Vue
	  //全局的Vue.options和new Vue的时候传入的属性合并之后的结果
	  vm.$options = mergeOptions(vm.constructor.options, options);
	  callHook(vm, "beforeCreate"); //初始化数据之前
	  // 初始化状态
	  initState(vm);
	  callHook(vm, "created"); //初始化数据之后
	  // 如果有el属性 进行模板渲染
	  if (vm.$options.el) {
	    vm.$mount(vm.$options.el);
	  }
	};
}

挂载组件时的调用

// src/lifecycle.js
export function mountComponent(vm, el) {
  vm.$el = el;
  // 引入watcher的概念 这里注册一个渲染watcher 执行vm._update(vm._render())方法渲染视图
  callHook(vm, "beforeMount"); //初始渲染之前
  let updateComponent = () => {
    vm._update(vm._render());
  };
  new Watcher(
    vm,
    updateComponent,
    () => {
      callHook(vm, "beforeUpdate"); //更新之前
    },
    true
  );
  callHook(vm, "mounted"); //渲染完成之后
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值