vue源码分析【8】-vue router路由

366 阅读1分钟

vue源码分析【8】-vue router路由

以下代码和分析过程需要结合vue.js源码查看,通过打断点逐一比对。

1.beforeCreate

先梳理下执行流程

  • new Vue前,首先会执行initMixin(Vue); ,但是此时只是挂载一个_init到Vue上,并没有执行_init。
  • 接着,执行 new Vue(引入Vue文件后,html或者main.js最终要有这个入口)进入function Vue(options)
  • 再执行this._init(options);,进入initMixin中的Vue.prototype._init = function (options)
  • 执行 callHook(vm, 'beforeCreate'); ,触发beforeCreate钩子函数

callHook:

    //触发生命周期钩子函数
    function callHook(
        vm,  //Vue 实例
        hook //钩子函数的key
    ) {
        // #7573 disable dep collection when invoking lifecycle hooks
        //调用生命周期钩子时禁用dep集合
        //Dep.target = _target; //存储
        pushTarget();
        //获取在vm 中添加的声明周期函数
        // 【说明2 vm.$option】
        var handlers = vm.$options[hook];
        if (handlers) {  //数组
            for (var i = 0, j = handlers.length; i < j; i++) {
                try {
                    // 执行生命周期函数
                    /**
                     *  比如我们在组件的beforeCreate钩子中写了如下代码:
                        beforeCreate() {
                            console.log(this,'====beforeCreate钩子函数')
                        }

                        handlers[i].call(vm)就会执行beforeCreate钩子函数里面的代码,
                        并且这里面的this指向传如vm,即Vue
                        【图1 执行beforeCreate打印this】
                     */
                    debugger
                    handlers[i].call(vm);
                } catch (e) {
                    handleError(e, vm, (hook + " hook"));
                }
            }
        }
        /**
         * 判断有没有这种hook方式来调用生命周期钩子:
         * <el-select ref="select" @hook:mounted="callback"></el-select>
         */
        if (vm._hasHookEvent) {
            vm.$emit('hook:' + hook);
        }
        // 出栈一个pushTarget
        popTarget();
    }

【说明1 pushTarget】,由于前面没有传参,所以这里_target为空。将Dep的target添加到targetStack,同时Dep的target更新为当前watcher对象

    // Dep是订阅者Watcher对应的数据依赖
    var Dep = function Dep() {
        //uid  初始化为0,每个Dep都有唯一的ID
        this.id = uid++;
        /* subs用于存放Watcher的依赖 */
        this.subs = [];
    };
    Dep.target = null; //初始化为null,最终通过pushTarget更新
    // 目标堆栈
    var targetStack = [];

    function pushTarget(_target) {
        if (Dep.target) { //target 是Watcher; 静态标志
            targetStack.push(Dep.target);// 集中管理Dep.target
        }
        Dep.target = _target;// 更新为当前传入的target
    }

popTarget

    function popTarget() {
        // 出栈一个pushTarget
        // pop()删除并返回数组的最后一个元素。
        Dep.target = targetStack.pop();
    }

【说明2 vm.$option】,可以看到这上面已经有了生命周期的相关函数了,那么,他是在哪里定义的呢?我们往前推,可以看到initMixin(Vue)有这样一段代码:

vm.$options = mergeOptions(
           // 解析constructor上的options属性的
              resolveConstructorOptions(vm.constructor), 
              // 这个options是function Vue(options)传进来的,即new Vue()传进来的,在那里,
              // 我们会自己在组件上定义相关的生命周期和相关的方法,属性
              options || {},
              vm
);

【图1 执行beforeCreate打印this】 image.png

2. created

执行完beforeCreate接着就会执行created。

在initMixin执行:

callHook(vm, 'created'); //触发created钩子函数

3. beforeMount

在mountComponent(){}执行:

callHook(vm, 'beforeMount');

它的执行顺序是这样的:

  • new Vue前,首先会执行initMixin(Vue); ,但是此时只是挂载一个_init到Vue上,并没有执行_init。
  • 接着,执行 new Vue(引入Vue文件后,html或者main.js最终要有这个入口)进入function Vue(options)
  • 再执行this._init(options);,进入initMixin中的Vue.prototype._init = function (options)
  • 执行 callHook(vm, 'beforeCreate'); ,触发beforeCreate钩子函数
  • 执行 callHook(vm, 'created'); ,触发created钩子函数
  • 执行最后一步的vm.$mount(vm.$options.el);,执行末尾的mount,Vue.prototype.$mount = function(),生成render渲染函数和真实的dom
  • 函数的最后,返回mount.call( this, el, hydrating),这时会进入文件中间的mount函数,Vue.prototype.$mount = function()
  • 然后执行mountComponent( this, el, hydrating),挂载组件,渲染页面。
  • 此时,我们就可以看到真实的dom了。

4. mounted

在mountComponent(){}执行:

        if (vm.$vnode == null) {
            vm._isMounted = true;
            //执行生命周期函数mounted
            // 渲染data
            callHook(vm, 'mounted');
        }

源码提问

1. Vue3.0的改进?

  • 采用了TS来编写
  • 支持composition API
  • 响应式数据原理改成了proxy
  • diff对比算法更新,只更新vdom绑定了动态数据的部分

2. 实现hash路由和history路由

  • onhashchange #
  • history.pushState h5 api

3. Vue-Router中导航守卫有哪些

image.png