Vue之Watcher源码解析(2)


Posted in Javascript onJuly 19, 2017

接着上节Vue Watcher源码的话,继续探讨,目前是这么个过程:

Vue之Watcher源码解析(2)

函数大概是这里:

// 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已经返回了,来看看是个啥:

Vue之Watcher源码解析(2)

Vue之Watcher源码解析(2)

这是一个虚拟节点,由之前字符串化后的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...
    }
  }

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

Vue之Watcher源码解析(2)

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

Javascript 相关文章推荐
javascript中的对象和数组的应用技巧
Jan 07 Javascript
关于javascript function对象那些迷惑分析
Oct 24 Javascript
实现非常简单的js双向数据绑定
Nov 06 Javascript
Bootstrap三种表单布局的使用方法
Jun 21 Javascript
使用Bootstrap typeahead插件实现搜索框自动补全的方法
Jul 07 Javascript
AngularJS ng-mousedown 指令
Aug 02 Javascript
详解js的延迟对象、跨域、模板引擎、弹出层、AJAX【附实例下载】
Dec 19 Javascript
Node.js利用断言模块assert进行单元测试的方法
Sep 28 Javascript
浅谈Node模块系统及其模式
Nov 17 Javascript
ReactNative之FlatList的具体使用方法
Nov 29 Javascript
vue.js表单验证插件(vee-validate)的使用教程详解
May 23 Javascript
JavaScript实现消消乐的源代码
Jan 12 Javascript
Angular.js项目中使用gulp实现自动化构建以及压缩打包详解
Jul 19 #Javascript
JS+canvas实现的五子棋游戏【人机大战版】
Jul 19 #Javascript
Vue学习笔记进阶篇之vue-router安装及使用方法
Jul 19 #Javascript
Vue学习笔记进阶篇之单元素过度
Jul 19 #Javascript
jQuery实现可编辑表格并生成json结果(实例代码)
Jul 19 #jQuery
jQuery实现导航栏头部菜单项点击后变换颜色的方法
Jul 19 #jQuery
利用require.js与angular搭建spa应用的方法实例
Jul 19 #Javascript
You might like
一键生成各种尺寸Icon的php脚本(实例)
2017/02/08 PHP
php获取是星期几的的一些常用姿势
2019/12/15 PHP
Avengerls vs KG BO3 第一场2.18
2021/03/10 DOTA
js类中的公有变量和私有变量
2008/07/24 Javascript
javascript 复杂的嵌套环境中输出单引号和双引号
2009/05/26 Javascript
突发奇想的一个jquery插件
2010/11/19 Javascript
js获取url参数代码实例分享(JS操作URL)
2013/12/13 Javascript
nodejs获取本机内网和外网ip地址的实现代码
2014/06/01 NodeJs
JavaScript中的getTimezoneOffset()方法使用详解
2015/06/10 Javascript
不依赖Flash和任何JS库实现文本复制与剪切附源码下载
2015/10/09 Javascript
JavaScript的String字符串对象常用操作总结
2016/05/26 Javascript
BootStrap 轮播插件(carousel)支持左右手势滑动的方法(三种)
2016/07/07 Javascript
多种方式实现js图片预览
2016/12/12 Javascript
AngularJS中的Promise详细介绍及实例代码
2016/12/13 Javascript
js实现登录框鼠标拖拽效果
2017/03/09 Javascript
JS操作xml对象转换为Json对象示例
2017/03/25 Javascript
vue实现导航栏效果(选中状态刷新不消失)
2017/12/13 Javascript
Vue中"This dependency was not found"问题的解决方法
2018/06/19 Javascript
JS 5种遍历对象的方式
2020/06/16 Javascript
详解element-ui 表单校验 Rules 配置 常用黑科技
2020/07/11 Javascript
python获取外网ip地址的方法总结
2015/07/02 Python
Python的Django框架中的表单处理示例
2015/07/17 Python
Python插件virtualenv搭建虚拟环境
2017/11/20 Python
使用Python OpenCV为CNN增加图像样本的实现
2019/06/10 Python
python库skimage给灰度图像染色的方法示例
2020/04/27 Python
Python爬虫爬取新闻资讯案例详解
2020/07/14 Python
python实现双人五子棋(终端版)
2020/12/30 Python
PyQt5通过信号实现MVC的示例
2021/02/06 Python
教你使用Canvas处理图片的方法
2017/11/28 HTML / CSS
英国天然宝石首饰购买网站:Gemondo Jewellery
2018/10/23 全球购物
新学期开学标语
2014/06/30 职场文书
园艺专业毕业生求职信
2014/09/02 职场文书
无刑事犯罪记录证明
2014/09/18 职场文书
2015年学校消防安全工作总结
2015/10/14 职场文书
剧场版《转生恶役只好拔除破灭旗标》公开最新视觉图 2023年上映
2022/04/02 日漫
python创建字典及相关管理操作
2022/04/13 Python