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 23 Javascript
Javascript中call的两种用法实例
Dec 13 Javascript
AngularJS内置指令
Feb 04 Javascript
js实现两点之间画线的方法
May 12 Javascript
使用javascript提交form表单方法汇总
Jun 25 Javascript
JavaScript性能优化总结之加载与执行
Aug 11 Javascript
es6中的解构赋值、扩展运算符和rest参数使用详解
Sep 28 Javascript
详解js常用分割取字符串的方法
May 15 Javascript
javascript面向对象创建对象的方式小结
Jul 29 Javascript
JavaScript常用工具函数大全
May 06 Javascript
vue操作dom元素的3种方法示例
Sep 20 Javascript
让你30分钟快速掌握vue3教程
Oct 26 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
蝙蝠侠:侠影之谜
2020/03/04 欧美动漫
php抓即时股票信息
2006/10/09 PHP
PHP array_multisort() 函数的深入解析
2013/06/20 PHP
PHP5.5迭代生成器用法实例详解
2016/03/16 PHP
php使用PDO从数据库表中读取数据的实现方法(必看)
2017/06/02 PHP
PDO::commit讲解
2019/01/27 PHP
Ruffy javascript 学习笔记
2009/11/30 Javascript
js获取单元格自定义属性值的代码(IE/Firefox)
2010/04/05 Javascript
Javascript实现视频轮播在pc端与移动端均可
2013/09/29 Javascript
简单js代码实现selece二级联动(推荐)
2014/02/18 Javascript
PHP结合jQuery实现红蓝投票功能特效
2015/07/22 Javascript
Bootstrap源码解读表单(2)
2016/12/22 Javascript
详解Node 定时器
2018/02/26 Javascript
jquery获取select选中值的文本,并赋值给另一个输入框的方法
2018/08/21 jQuery
Vue项目中最新用到的一些实用小技巧
2018/11/06 Javascript
Vue组件教程之Toast(Vue.extend 方式)详解
2019/01/27 Javascript
详解vue引入子组件方法
2019/02/12 Javascript
详解小程序中h5页面onShow实现及跨页面通信方案
2019/05/30 Javascript
JavaScript直接调用函数与call调用的区别实例分析
2020/05/22 Javascript
[01:32]2014DOTA2西雅图邀请赛 CIS我们有信心进入正赛
2014/07/08 DOTA
使用PDB简单调试Python程序简明指南
2015/04/25 Python
python开发利器之ulipad的使用实践
2017/03/16 Python
Python配置mysql的教程(推荐)
2017/10/13 Python
使用Python从零开始撸一个区块链
2018/03/14 Python
python3.6使用pickle序列化class的方法
2018/10/22 Python
python-opencv 将连续图片写成视频格式的方法
2019/01/08 Python
用Python从0开始实现一个中文拼音输入法的思路详解
2019/07/20 Python
Python实现CNN的多通道输入实例
2020/01/17 Python
10个python爬虫入门基础代码实例 + 1个简单的python爬虫完整实例
2020/12/16 Python
HTML5 Canvas中绘制椭圆的4种方法
2015/04/24 HTML / CSS
使用分层画布来优化HTML5渲染的教程
2015/05/08 HTML / CSS
运动会加油稿20字
2014/11/15 职场文书
网吧员工管理制度
2015/08/05 职场文书
nginx里的rewrite跳转的实现
2021/03/31 Servers
人物搭配车车超萌联名预备中 【咒术迴战】 ⨯ 【天竺鼠车车】 展开合作
2022/04/11 日漫
pd.DataFrame中的几种索引变换的实现
2022/06/16 Python