• Vue源码后记-钩子函数


      vue源码的马拉松跑完了,可以放松一下写点小东西,其实源码讲20节都讲不完,跳了好多地方。

      本人技术有限,无法跟大神一样,模拟vue手把手搭建一个MVVM框架,然后再分析原理,只能以门外汉的姿态简单过一下~

      想到什么写什么了,这节就简单说说钩子函数吧!

      vue中的钩子函数主要包含初始化的beforeCreated/created,Virtual Dom更新期间的beforeUpdate/updated,页面渲染期间的beforeMount/mounted,组件销毁期间的beforeDestroy/destroyed等等。

      vue框架会在合适的时间点调用对应的钩子函数,调用过程其实很简单,看一下源码的函数就明白了:

        // vm为当前vue实例
        // hook为钩子函数名称
        function callHook(vm, hook) {
            // 获取对相应的钩子函数内容
            var handlers = vm.$options[hook];
            if (handlers) {
                for (var i = 0, j = handlers.length; i < j; i++) {
                    try {
                        // 直接调用
                        handlers[i].call(vm);
                    } catch (e) {
                        handleError(e, vm, (hook + " hook"));
                    }
                }
            }
            // 钩子函数事件emit
            if (vm._hasHookEvent) {
                vm.$emit('hook:' + hook);
            }
        }

      其中vm.$option中包含了vm中所有的钩子函数已经其他一些配置,根据对应的hook字符串取出来然后用call执行。

      可以从一个简单的例子跑一遍:

        <body>
            <div id='app'>
                {{message}}
            </div>
        </body>
        <script src='./vue.js'></script>
        <script>
            var app = new Vue({
                el: '#app',
                data: {
                    message: 'Hello Vue!'
                },
                beforeCreate: function() {
                    console.log('beforeCreate');
                }
            });
        </script>

      样本案例还是之前跑源码的,只不过在这里额外加了一个钩子函数,随便选了一个beforeCreate。

      跑源码我写过,对象会以options对象的形式与baseOptions进行合并处理,如下:

        Vue.prototype._init = function() {
            // code...
    
            vm.$options = mergeOptions(
                resolveConstructorOptions(vm.constructor),
                options || {},
                vm
            );
    
            // code...
        }

      其options就是new Vue传进来的那个对象,mergeOptions如下:

        function mergeOptions(parent, child, vm) {
            // code...
            for (key in child) {
                if (!hasOwn(parent, key)) {
                    mergeField(key);
                }
            }
    
            function mergeField(key) {
                var strat = strats[key] || defaultStrat;
                options[key] = strat(parent[key], child[key], vm, key);
            }
            return options
        }

      其余的属性都跳过,目前主关注钩子函数的处理。函数内部会遍历child(即传进来的对象),然后根据键名取对应strats对象的函数对值进行处理。

      可以简略看一下strats对象:,基本上包含所有可能的键,无论是钩子函数、值、计算属性、方法等,所有的参数会被处理。

      而beforeCreate参数被分类为钩子函数,会调用mergeHook函数,源码如下:

        // parentVal => undefined
        // childVal => function(){...}
        function mergeHook(parentVal, childVal) {
            return childVal ?
                parentVal ?
                parentVal.concat(childVal) :
                Array.isArray(childVal) ?
                childVal : [childVal] :
                parentVal
        }

      这个函数同时也处理props属性,所以接受两个参数。如果是钩子函数,则parentVal为undefined,这个超长三元表达式稍微解说一下:

      childVal有没有?有啊,好,那parentVal呢?没,那childVal是不是数组啊?不是,是个函数。好,包起来,弄成数组返回吧!

      于是,最终钩子函数被包装了这样:

      

      现在,回到最开始那个callHook函数,就能跑得通了。handlers就是这个数组,for循环遍历,取出函数,调用call方法执行钩子函数代码,看情况emit一下,返回。

      

      钩子函数的作用我就不解释了,这个网上随便查都有,我就简单说说为什么要在created中调用ajax初始化数据,一起来看看源码:

        function initMixin(Vue) {
            // code...
    
            initLifecycle(vm);
            initEvents(vm);
            initRender(vm);
            callHook(vm, 'beforeCreate');
            initInjections(vm); // resolve injections before data/props
            initState(vm);
            initProvide(vm); // resolve provide after data/props
            callHook(vm, 'created');
    
            // code...
        }

      在beforeCreate阶段,vue仅仅完成了参数合并,以及在vm上添加了大量空属性,并没有实际开始初始化操作,这时候如果调用ajax,并调用this.data你会发现:

      对的,压根就没有这个属性。

      但是,在之后的initState初始化中(有兴趣可以回头看下我的流水账呀),会将data属性解析并添加到vm上,并且已经有对应的响应式方法了。

      所以说,这个时候页面还没有渲染,非常适合进行数据初始化。

      

      背不来网上的生命周期,自己画个图:

      

      

      

  • 相关阅读:
    WPF:linq
    WPF:ListView数据绑定及Style
    WPF: DatePicker
    多线程16--单例--懒汉模式和静态内部类形
    多线程15--线程本地变量ThreadLocal
    多线程14---模拟消息队列
    多线程13--多线程并发购票--低效的线程安全的车票容器
    多线程10--线程间实时通信--耗性能的轮询
    自定义video的controls(播放暂停按钮、进度条、快进快退等)
    js+css 写出 简单2048游戏
  • 原文地址:https://www.cnblogs.com/QH-Jimmy/p/7264639.html
Copyright © 2020-2023  润新知