• .11-Vue源码之patch(1)


    最近太鸡儿忙了!鸽了一个多月,本来这个都快完了,拖到现在,结果我都不知道怎么写了。

      接着上节的话,目前是这么个过程:

      函数大概是这里:

        // line-3846
        Vue.prototype._render = function() {
    
            // 获取参数
    
            try {
                // 死在这儿
                vnode = render.call(vm._renderProxy, vm.$createElement);
            } catch (e) {
                // 报render错误
            }
            // return empty vnode in case the render function errored out
            if (!(vnode instanceof VNode)) {
                // 返回空节点
            }
            // set parent
            vnode.parent = _parentVnode;
            return vnode
        };

      然后,在上个月,我卡死在了render.call这个函数上面,因为所有vue实例被设置了proxy代理,所以会跳转到各种奇怪的检测函数中。

      过了一个月,我依然看不懂,一点都不想讲,所以先跳过,直接看后面!

      

      这里假设vnode已经返回了,来看看是个啥:

      这是一个虚拟节点,由之前字符串化后的DOM树生成,主要包含子节点、上下文、属性、文本、标签名、类型等属性,这些可以直接从键名判断。

       

      得到vnode后,由于这里是根节点,所以不存在_parentVnode,直接返回。

      然后到了mountComponent函数:

        // line-2374
        function mountComponent(vm, el, hydrating) {
            vm.$el = el;
            // error
            callHook(vm, 'beforeMount');
    
            var updateComponent;
            /* istanbul ignore if */
            if ("development" !== 'production' && config.performance && mark) {
                updateComponent = function() {
                    // 开发者模式下的处理方式
                };
            } else {
                // 重新进入这里
                updateComponent = function() {
                    vm._update(vm._render(), hydrating);
                };
            }
    
            vm._watcher = new Watcher(vm, updateComponent, noop);
            hydrating = false;
    
            // manually mounted instance, call mounted on self
            // mounted is called for render-created child components in its inserted hook
            if (vm.$vnode == null) {
                vm._isMounted = true;
                callHook(vm, 'mounted');
            }
            return vm
        }

      这样,就带着返回的vode进入了_update函数,开始正式渲染页面。

      函数如下:

        // line-2374
        Vue.prototype._update = function(vnode, hydrating) {
            var vm = this;
            if (vm._isMounted) {
                callHook(vm, 'beforeUpdate');
            }
            // 保存原属性
            var prevEl = vm.$el;
            var prevVnode = vm._vnode;
            var prevActiveInstance = activeInstance;
            activeInstance = vm;
            vm._vnode = vnode;
            // patch
            if (!prevVnode) {
                // 初始化渲染
                vm.$el = vm.__patch__(
                    vm.$el, vnode, hydrating, false /* removeOnly */ ,
                    vm.$options._parentElm,
                    vm.$options._refElm
                );
            } else {
                // 更新
                vm.$el = vm.__patch__(prevVnode, vnode);
            }
            activeInstance = prevActiveInstance;
            // update __vue__ reference
            if (prevEl) {
                prevEl.__vue__ = null;
            }
            if (vm.$el) {
                vm.$el.__vue__ = vm;
            }
            // if parent is an HOC, update its $el as well
            // HOC => High Order Component => 高阶组件
            if (vm.$vnode && vm.$parent && vm.$vnode === vm.$parent._vnode) {
                vm.$parent.$el = vm.$el;
            }
            // updated hook is called by the scheduler to ensure that children are
            // updated in a parent's updated hook.
        };

      由于是初次渲染,所以会进入第一个条件分支,并调用__patch__函数,传入原生DOM节点、虚拟DOM、false三个参数。

      __patch__在加载框架时候已经注入了,见代码:

        // line-7526
        // install platform patch function
        Vue$3.prototype.__patch__ = inBrowser ? patch : noop;
    
        // line-6968
        var patch = createPatchFunction({
            nodeOps: nodeOps,
            modules: modules
        });

      这里,nodeOps为封装的DOM操作操作方法,modules为属性、指令等相关方法。

      这个createPatchFunction函数的构造相当于一个模块,里面包含大量的方法,但是最后不是返回一个对象包含内部方法的引用,而是返回一个函数,形式大概如下:

        // line-4762
        function createPatchFunction() {
            // fn1...
            // fn2...
            return function patch() {
                // 调用内部方法fn1,fn2...
            }
        }

      方法比较多,下次再讲,边跑流程边看。

      

  • 相关阅读:
    Ubuntu18.04下使用pip3.8报错subprocess.CalledProcessError: Command ‘(‘lsb_release‘, ‘-a‘)‘ returned non-ze
    解决报错:ModuleNotFoundError: No module named ‘_sqlite3‘
    shell命令中find的用法
    Ubuntu 中卸载软件
    git使用
    django celery 使用
    Django 学习中遇到的问题
    1
    Mac 下安装brew(文末方法亲测有效)
    经典类与新式类的继承顺序
  • 原文地址:https://www.cnblogs.com/QH-Jimmy/p/7201758.html
Copyright © 2020-2023  润新知