Vue实例初始化完成后,启动加载($mount)模块数据。

(一)Vue$3.protype.$mount

      

        标红的函数 compileToFunctions 过于复杂,主要是生AST 树,返回的 ref 如下:

      

render 是浏览器虚拟机编译出来的一个函数。我们点进入可以看到如下代码(自己调整后空格换行后的数据) 

  1. (function(){
  2. with(this){
  3. return _c('div',{
  4. attrs:{"id":"app"}},
  5. [_c('input',{directives:[{name:"model",rawName:"v-model",value:(message),expression:"message"}],
  6. attrs:{"type":"text"},domProps:{"value":(message)},
  7. on:{"input":function($event){
  8. if($event.target.composing)return;message=$event.target.value}}}),
  9. _v(_s(message)+"\n")])
  10. }
  11. })

  跳过这个复杂的函数。

  这里作者涉及的很奇妙,因为 mount.call(this, el, hydrating)  中的 mount 定义如下

  var mount = Vue$3.prototype.$mount;

  1. Vue$.prototype.$mount = function (el, hydrating) {
  2. el = el && inBrowser ? query(el) : undefined;
  3. return mountComponent(this, el, hydrating) //vm._watcher 赋值
  4. };

  后来又重写了$mount 方法:

  Vue$3.prototype.$mount = function (el, hydrating) {   }

(二)mountComponent () 函数

组件安装

  1. function mountComponent(vm, el, hydrating) {
  2. vm.$el = el;
  3. if (!vm.$options.render) {
  4. //如果不存咋,则创建一个空的虚拟节点
  5. vm.$options.render = createEmptyVNode;
  6. }
  7. callHook(vm, 'beforeMount');
  8.  
  9. var updateComponent;
  10. if ("development" !== 'production' && config.performance && mark) {
  11. //此处另一种 updateComponent = 。。。。
  12. } else {
  13. updateComponent = function () {
  14. vm._update(vm._render(), hydrating); //渲染DOM
  15. };
  16. }
  17. //noop 空函数,
  18. vm._watcher = new Watcher(vm, updateComponent, noop); //生成中间件 _watcher
  19. hydrating = false;
  20.  
  21. // $vnode不存在,,则手动安装实例,自启动
  22. // mounted is called for render-created child components in its inserted hook
  23. if (vm.$vnode == null) {
  24. vm._isMounted = true;
  25. callHook(vm, 'mounted');
  26. }
  27. return vm //调用 实例加载钩子函数,返回vue实例
  28. }

  Watcher是一个十分复杂的对象,是沟通 Observer与 Compile 的桥梁作用。

(3)Watcher对象

     1、构造函数

   Watcher的构造函数并不复杂,主要是为当前Watcher 初始化各种属性,比如depIds,newDeps,getter 等,

  最后调用 Watcher.prototype.get(),让Dep收集此Wather实例。

   

  Watcher构造函数会将 传入的第二个参数转换 this.getter 属性;

  由于 this.lazy=false,会立即进入 Watcher.prototype.get()。

2、Watcher.prototype.get()

  绕了一大圈,这个函数其实也就调用了 传入构造函数的第二个参数。

  1. Watcher.prototype.get = function get() {
  2. pushTarget(this);
  3. var value;
  4. var vm = this.vm;
  5. try {
  6. //初始化时 最终 调用我们传入的 updateComponent
  7. // vm._update(vm._render(), hydrating)
  8. value = this.getter.call(vm, vm);
  9. } catch (e) {
  10. } finally {
  11. if (this.deep) {
  12. traverse(value);
  13. }
  14. popTarget();
  15. this.cleanupDeps();
  16. }
  17. return value
  18. };

此时 this.getter = vm._update(vm._render(), hydrating);  开始渲染渲染DOM,这里十分重要。

先 执行 Vue.prototype._render(),代码如下

 

这里 render 便是生成的AST代码。

接下来会按照 如下顺序 触发各种函数:

代理函数 proxyGetter() ==>  reactiveGetter() => 执行 render里面的函数 _c ;

执行完后,将创建的vnode直接返回。

让我们再仔细看看 defineReactive$$1() 函数,为元素自定义get/set方法。

  1. function defineReactive$$(obj, key, val, customSetter, shallow) {
  2. var dep = new Dep();//依赖管理
  3. /* 此时obj 是带有__ob__属性的对象,key是msg */
  4. var property = Object.getOwnPropertyDescriptor(obj, key);//返回键描述信息
  5. if (property && property.configurable === false) {
  6. //不可以修改直接返回
  7. return
  8. }
  9.  
  10. var getter = property && property.get;
  11. var setter = property && property.set;
  12.  
  13. var childOb = !shallow && observe(val);
  14. Object.defineProperty(obj, key, {
  15. enumerable: true,
  16. configurable: true,
  17. get: function reactiveGetter() {
  18. var value = getter ? getter.call(obj) : val;
  19. if (Dep.target) {
  20. dep.depend();
  21. if (childOb) {
  22. childOb.dep.depend();
  23. if (Array.isArray(value)) {
  24. dependArray(value);
  25. }
  26. }
  27. }
  28. return value
  29. },
  30. set: function reactiveSetter(newVal) {
  31. var value = getter ? getter.call(obj) : val; //获取当前值,是前一个值
  32. if (newVal === value || (newVal !== newVal && value !== value)) {
  33. //值没有发生变化,不再做任何处理
  34. return
  35. }
  36. /* eslint-enable no-self-compare */
  37. if ("development" !== 'production' && customSetter) {
  38. customSetter();
  39. }
  40. if (setter) {
  41. setter.call(obj, newVal);//调用默认setter方法或将新值赋给当前值
  42. } else {
  43. val = newVal;
  44. }
  45. childOb = !shallow && observe(newVal);
  46. dep.notify();//赋值后通知依赖变化
  47. }
  48. });
  49. }

defineReactive$$1

说的不太清楚,下篇文章继续说。

Vue源码学习(二)$mount() 后的做的事(1)的更多相关文章

  1. Vue源码学习1——Vue构造函数

    Vue源码学习1--Vue构造函数 这是我第一次正式阅读大型框架源码,刚开始的时候完全不知道该如何入手.Vue源码clone下来之后这么多文件夹,Vue的这么多方法和概念都在哪,完全没有头绪.现在也只 ...

  2. Vue源码学习三 ———— Vue构造函数包装

    Vue源码学习二 是对Vue的原型对象的包装,最后从Vue的出生文件导出了 Vue这个构造函数 来到 src/core/index.js 代码是: import Vue from './instanc ...

  3. Vue源码学习二 ———— Vue原型对象包装

    Vue原型对象的包装 在Vue官网直接通过 script 标签导入的 Vue包是 umd模块的形式.在使用前都通过 new Vue({}).记录一下 Vue构造函数的包装. 在 src/core/in ...

  4. 最新 Vue 源码学习笔记

    最新 Vue 源码学习笔记 v2.x.x & v3.x.x 框架架构 核心算法 设计模式 编码风格 项目结构 为什么出现 解决了什么问题 有哪些应用场景 v2.x.x & v3.x.x ...

  5. 【Vue源码学习】依赖收集

    前面我们学习了vue的响应式原理,我们知道了vue2底层是通过Object.defineProperty来实现数据响应式的,但是单有这个还不够,我们在data中定义的数据可能没有用于模版渲染,修改这些 ...

  6. Vue 源码学习(1)

    概述 我在闲暇时间学习了一下 Vue 的源码,有一些心得,现在把它们分享给大家. 这个分享只是 Vue源码系列 的第一篇,主要讲述了如下内容: 寻找入口文件 在打包的过程中 Vue 发生了什么变化 在 ...

  7. 【Vue源码学习】响应式原理探秘

    最近准备开启Vue的源码学习,并且每一个Vue的重要知识点都会记录下来.我们知道Vue的核心理念是数据驱动视图,所有操作都只需要在数据层做处理,不必关心视图层的操作.这里先来学习Vue的响应式原理,V ...

  8. Vue源码学习(一):调试环境搭建

    最近开始学习Vue源码,第一步就是要把调试环境搭好,这个过程遇到小坑着实费了点功夫,在这里记下来 一.调试环境搭建过程 1.安装node.js,具体不展开 2.下载vue项目源码,git或svn等均可 ...

  9. VUE 源码学习01 源码入口

    VUE[version:2.4.1] Vue项目做了不少,最近在学习设计模式与Vue源码,记录一下自己的脚印!共勉!注:此处源码学习方式为先了解其大模块,从宏观再去到微观学习,以免一开始就研究细节然后 ...

  10. Dubbo源码学习(二)

    @Adaptive注解 在上一篇ExtensionLoader的博客中记录了,有两种扩展点,一种是普通的扩展实现,另一种就是自适应的扩展点,即@Adaptive注解的实现类. @Documented ...

随机推荐

  1. YAML快速入门

    https://www.jianshu.com/p/97222440cd08 我们学习Java,都是先介绍properties文件,使用properties文件配合Properties对象能够很方便的 ...

  2. (转)K-近邻算法(KNN)

    K-近邻算法(KNN)概述  KNN是通过测量不同特征值之间的距离进行分类.它的思路是:如果一个样本在特征空间中的k个最相似(即特征空间中最邻近)的样本中的大多数属于某一个类别,则该样本也属于这个类别 ...

  3. 记录Redis使用中遇到的两个问题(原子性及数据完整性)

    1.使用Redis作为分布式锁的原子性问题 原方案: ① SETNX $LOCK_BUSI_KEY $REQ_ID ② EXPIRE $LOCK_BUSI_KEY $LOCK_TIME 问题: 使用S ...

  4. 高性能 TCP & HTTP 通信框架 HP-Socket v4.3.1

    HP-Socket 是一套通用的高性能 TCP/UDP/HTTP 通信框架,包含服务端组件.客户端组件和 Agent 组件,广泛适用于各种不同应用场景的 TCP/UDP/HTTP 通信系统,提供 C/ ...

  5. ubuntu下多版本OpenCV的共存与使用

    首先,OpenCV历史版本下载:https://www.opencv.org/releases.html 一.把不同版本的OpenCV安装在不同位置 下载好OpenCV源码,在安装之前打开CMakeL ...

  6. 微服务架构基础之Service Mesh

    ServiceMesh(服务网格) 概念在社区里头非常火,有人提出 2018 年是 ServiceMesh 年,还有人提出 ServiceMesh 是下一代的微服务架构基础. 那么到底什么是 Serv ...

  7. Maintaining ICM Parameters for Using SSL for As JAVA

    1770585 - How to configure SSL on the AS Java You can use this procedure to configure the necessary ...

  8. ssm注入失败

    今天做ssm整合时候,创建bean/注入一直出错,检查几遍没发现问题,后来发现犯了个低级错误,mapper.xml的<mapper namespace="XXXXX" > ...

  9. Split CSV/TXT file

    void Main(){ var path = @"c:\sourceGit\speciesLatLon.txt"; var inputLines = File.ReadAllLi ...

  10. url跳转漏洞(1)

    转载 https://landgrey.me/open-redirect-bypass/ 0x00:漏洞场景 URL跳转漏洞的出现场景还是很杂的,出现漏洞的原因大概有以下5个: 1. 写代码时没有考虑 ...