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 对象的属性和方法4种不同的类型
Mar 19 Javascript
JQuery入门—JQuery程序的代码风格详细介绍
Jan 03 Javascript
如何阻止复制剪切和粘贴事件为了表单内容的安全
May 23 Javascript
jquery属性选择器not has怎么写 行悬停高亮显示
Nov 13 Javascript
jquery 获取 outerHtml 包含当前节点本身的代码
Oct 30 Javascript
JavaScript Sort 的一个错误用法示例
Mar 20 Javascript
jQuery链式操作实例分析
Nov 16 Javascript
常常会用到的截取字符串substr()、substring()、slice()方法详解
Dec 16 Javascript
Bootstrap 3浏览器兼容性问题及解决方案
Apr 11 Javascript
使用Vue.js和Element-UI做一个简单登录页面的实例
Feb 23 Javascript
JSON字符串操作移除空串更改key/value的介绍
Jan 05 Javascript
Node.js fs模块(文件模块)创建、删除目录(文件)读取写入文件流的方法
Sep 03 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代码的53条建议
2008/03/27 PHP
基于OpenCV的PHP图像人脸识别技术
2009/10/11 PHP
PHP的运行机制与原理(底层)
2015/11/16 PHP
smarty学习笔记之常见代码段用法总结
2016/03/19 PHP
thinkPHP5框架路由常用知识点汇总
2019/09/15 PHP
基于jQuery实现的百度导航li拖放排列效果,即时更新数据库
2012/07/31 Javascript
jquery实现非叠加式的搜索框提示效果
2014/01/07 Javascript
使用AngularJS中的SCE来防止XSS攻击的方法
2015/06/18 Javascript
JavaScript截断字符串的方法
2015/07/15 Javascript
纯JS实现本地图片预览的方法
2015/07/31 Javascript
jQuery实现的超酷苹果风格图标滑出菜单效果代码
2015/09/16 Javascript
jQuery调用WebMethod(PageMethod) NET2.0的方法
2016/04/15 Javascript
js获取所有checkbox的值的简单实例
2016/05/30 Javascript
Bootstrap文件上传组件之bootstrap fileinput
2016/11/25 Javascript
jquery对所有input type=text的控件赋值实现方法
2016/12/02 Javascript
微信小程序 自己制作小组件实例详解
2016/12/22 Javascript
微信小程序实现缓存根据不同的id来进行设置和读取缓存
2017/06/12 Javascript
jQuery 实现双击编辑表格功能
2017/06/19 jQuery
vue脚手架中配置Sass的方法
2018/01/04 Javascript
JS+CSS3实现的简易钟表效果示例
2019/04/13 Javascript
微信小程序canvas开发水果老虎机的思路详解
2020/02/07 Javascript
Ant Design的Table组件去除
2020/10/24 Javascript
python主线程捕获子线程的方法
2018/06/17 Python
numpy返回array中元素的index方法
2018/06/27 Python
解决pycharm每次新建项目都要重新安装一些第三方库的问题
2019/01/17 Python
对python3 Serial 串口助手的接收读取数据方法详解
2019/06/12 Python
Pycharm新建模板默认添加个人信息的实例
2019/07/15 Python
在Python中使用filter去除列表中值为假及空字符串的例子
2019/11/18 Python
在keras中对单一输入图像进行预测并返回预测结果操作
2020/07/09 Python
CSS3 filter(滤镜)实现网页灰色或者黑色模式的代码
2020/11/30 HTML / CSS
美国奢侈品在线团购网站:Gilt City
2017/11/16 全球购物
2013年高中生自我评价
2013/10/23 职场文书
大学运动会入场词
2014/02/22 职场文书
教师校本培训方案
2014/02/26 职场文书
大一学生职业生涯规划
2014/03/11 职场文书
证劵公司反洗钱宣传活动总结
2015/05/08 职场文书