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 相关文章推荐
JS获取父节点方法
Aug 20 Javascript
IE6下出现JavaScript未结束的字符串常量错误的解决方法
Nov 21 Javascript
yepnope.js 异步加载资源文件
Sep 08 Javascript
JavaScript 命名空间 使用介绍
Aug 29 Javascript
JavaScript移除数组元素减少长度的方法
Sep 05 Javascript
JavaScript数组的栈方法与队列方法详解
May 26 Javascript
js中用cssText设置css样式的简单方法
Sep 19 Javascript
浅谈AngularJs 双向绑定原理(数据绑定机制)
Dec 07 Javascript
layui弹出层按钮提交iframe表单的方法
Aug 20 Javascript
Vue自定义属性实例分析
Feb 23 Javascript
layui的表单提交以及验证和修改弹框的实例
Sep 09 Javascript
Vue-cli3生成的Vue项目加载Mxgraph方法示例
May 31 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
php array_intersect比array_diff快(附详细的使用说明)
2011/07/03 PHP
php excel reader读取excel内容存入数据库实现代码
2012/12/06 PHP
使用gd库实现php服务端图片裁剪和生成缩略图功能分享
2013/12/25 PHP
PHP实现显示照片exif信息的方法
2014/07/11 PHP
PHP中定义数组常量(array常量)的方法
2014/11/17 PHP
详解PHP数据压缩、加解密(pack, unpack)
2016/12/17 PHP
php实现文件与16进制相互转换的方法示例
2017/02/16 PHP
PHP 自动加载类原理与用法实例分析
2020/04/14 PHP
JS Array对象入门分析
2008/10/30 Javascript
JQuery中判断一个元素下面是否有内容或者有某个标签的判断代码
2012/02/02 Javascript
JS上传图片前实现图片预览效果的方法
2015/03/02 Javascript
JS实现网页标题随机显示名人名言的方法
2015/11/03 Javascript
jQuery遍历DOM节点操作之filter()方法详解
2016/04/14 Javascript
AngularJs bootstrap搭载前台框架——js控制部分
2016/09/01 Javascript
javascript编程开发中取色器及封装$函数用法示例
2017/08/09 Javascript
使用vue与jquery实时监听用户输入状态的操作代码
2017/09/19 jQuery
[26:21]浴火之凤-TI4世界冠军Newbee战队纪录片
2014/08/07 DOTA
[02:17]DOTA2亚洲邀请赛 RAVE战队出场宣传片
2015/02/07 DOTA
[01:27:43]VGJ.S vs TNC Supermajor 败者组 BO3 第三场 6.6
2018/06/07 DOTA
用C++封装MySQL的API的教程
2015/05/06 Python
numpy使用技巧之数组过滤实例代码
2018/02/03 Python
使用numba对Python运算加速的方法
2018/10/15 Python
Python GUI编程 文本弹窗的实例
2019/06/11 Python
python 反编译exe文件为py文件的实例代码
2019/06/27 Python
详解Python 4.0 预计推出的新功能
2019/07/26 Python
Python模块/包/库安装的六种方法及区别
2020/02/24 Python
Python预测2020高考分数和录取情况
2020/07/08 Python
Finishline官网:美国一家领先的运动品牌鞋类、服装零售商
2016/07/20 全球购物
巴基斯坦电子产品购物网站:Home Shopping
2017/09/14 全球购物
国际书籍零售商:Wordery
2017/11/01 全球购物
海滩咖啡馆:Beach Cafe
2018/02/02 全球购物
2014新年元旦活动策划方案
2014/02/18 职场文书
篝火晚会主持词
2014/03/25 职场文书
2014幼儿园教师个人工作总结
2014/11/08 职场文书
《七律·长征》教学反思
2016/02/16 职场文书
iOS 16进一步确认,一共支持16款iPhone
2022/04/28 数码科技