Vue核心模块讲解

Vue.mixin的mergeOption合并策略

  1. Object.create(null)生成不带原型链的容器strats
  2. strats.el = strats.propsData:child === undefined ? parent : child
  3. strats.data = strats.provide:以child为主,递归合并
  4. strats.生命周期:合并到Array中
  5. strats.components = strats.directives = strats.filter:遍历child放到res中,res的原型指向parent
  6. strats.watch:合并到Array中
  7. strats.props = strats.methods = strats.inject = strats.computed:同名时child覆盖parent
  8. 其余:child === undefined ? parent : child

nextTick核心

  • 做什么的:下次 DOM 更新循环结束之后执行的延迟回调【使用最新的dom进行操作】

  • 核心:将任务放入队列callbacks中延迟执行,通过callbacks.slice(0)复制一份用于遍历执行,同时将callbacks.length = 0清空原数组。

  • 宏任务还是微任务:依次判断先微后宏【Promise - MutationObserver - setImmediate - setTimeout】

keep-alive核心

render函数:

  • 触发时机:首次渲染、插槽中的内容变化需要重新被渲染;
  • 做什么:获取到插槽中的组件实例用于缓存;

cacheVNode函数:

  • 触发时机:
    • 首次渲染在mounted钩子【放入缓存+监听include+监听exclude分别对缓存数组中的不需缓存组件实例进行销毁】
    • 插槽内容变化在updated钩子;
  • 做什么的:将插槽内容放入缓存;
  • 何时被清除:
    • 当达到设置的max最大缓存数,通过LRU(最近最少使用) 算法,选择最近最久未使用的组件予以淘汰。【通过缓存数组中第一个获取到最久未使用的组件实例】;
    • 当修改include、exclude时可能会被清除;
    • destroyed钩子全部清除;

数据响应式

Vue采用“推”的变化侦测模式,一个状态会绑定多个依赖,当变化时,通知对应的依赖进行Dom更新操作。【可以随意调整更新粒度】

Vue1.0:数据与Dom节点关联【细粒度】,依赖数量较多、内存开销较大。

Vue2.0:数据与虚拟Dom(组件)关联【中等粒度】,降低依赖数量及所依赖内存开销。

  1. 核心

    Object.defineProperty:getter收集依赖、setter触发依赖更新。事件中心Dep依赖Watcher

    弊端:

    • 当监听 “a.b.c” 时,当前Watcher会被a、a.b、a.b.c所依赖。仔细想想貌似也没毛病。
    • 对象【dep在defineReactive】新增 / 删除属性需要借助 s e t 和 set和 setdelete;
    • 数组【dep在】需拦截部分方法实现响应式,list[0]=2【Object.defineProperty可以实现item[0] = 2的响应,尤大出于性能代价和用户体验收益不成正比才放弃的】和list.length=0不能实现响应式

Vue.extend核心

  • 做什么的:当使用vue-cli方式进行开发时,大多数使用的SFC组件化生成 XXX.vue 页面,之后通过 Vue.extend实例化组件使用基础 Vue 构造器,创建一个“子类”。 VUe.component('', {})也是调用的该方法生成实例。
<script>
import Counter from './components/Counter';
import Vue from 'vue';
export default {
  name: 'App',
  components: {
    ButtonCounter,
  },
  methods: {
    insert() {
      const Counter = Vue.extend(Counter);	// 最终还是使用init初始化的
      const instance = new Counter();
      instance.$mount('#container');
    },
  },
};
</script>
  • 核心:
    • 使用原型继承的方法返回了 Vue 的子类 VueComponent 构造函数
    • 利用 mergeOptions 把传入组件的 options 和Vue.options 【包含使用Vue.use注册的插件: s t o r e 、 store、 storerouter等都在全局option】进行了合并。

自定义指令

应用参考

Vue.use

  • 做什么的:向Vue项目注册插件,比如:vuex、vue-router等

  • 核心:

    • 判断当前注册列表中是否已注册,注册过直接返回,没有注册继续向下;

    • 准备参数(第一个参数为全局Vue):const args = toArray(arguments, 1); args.unshift(this /** 表示全局Vue **/)

    • 运行插件的install方法:plugin.install.apply(plugin, args);否则直接运行 plugin.apply(null, args)

      • vue-router为例:

        • 在项目开始注册 import VueRouter from "vue-router"; Vue.use(VueRouter);

        • 运行install方法:

          export let _Vue
          export function install (Vue) {
            // 1. 确保只能注册一次
            if (install.installed && _Vue === Vue) return
            install.installed = true
          
            _Vue = Vue
          
            const isDef = v => v !== undefined
          
            const registerInstance = (vm, callVal) => {
              let i = vm.$options._parentVnode
              if (isDef(i) && isDef(i = i.data) && isDef(i = i.registerRouteInstance)) {
                i(vm, callVal)
              }
            }
            // 2. 向全局Vue.mixins添加钩子[将router逻辑代码插入];之后通过Vue.extends生成的组件都会混入
            Vue.mixin({
              beforeCreate () {
                if (isDef(this.$options.router)) {
                  this._routerRoot = this
                  this._router = this.$options.router
                  this._router.init(this)
                  Vue.util.defineReactive(this, '_route', this._router.history.current)
                } else {
                  this._routerRoot = (this.$parent && this.$parent._routerRoot) || this
                }
                registerInstance(this, this)
              },
              destroyed () {
                registerInstance(this)
              }
            })
            // 3. 向Vue.prototype添加$router和$route属性
            Object.defineProperty(Vue.prototype, '$router', {
              get () { return this._routerRoot._router }
            })
            Object.defineProperty(Vue.prototype, '$route', {
              get () { return this._routerRoot._route }
            })
            // 4. 注册全局组件RouterView和RouterLink
            Vue.component('RouterView', View)
            Vue.component('RouterLink', Link)
              
            // 5. 设置beforeRouteEnter、beforeRouteLeave、beforeRouteUpdate的合并策略
            const strats = Vue.config.optionMergeStrategies
            strats.beforeRouteEnter = strats.beforeRouteLeave = strats.beforeRouteUpdate = strats.created
          }
          
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值