Vue源码学习(二)$mount() 后的做的事(1)

时间:2022-09-01 09:00:32

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

(一)Vue$3.protype.$mount

      Vue源码学习(二)$mount() 后的做的事(1)

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

      Vue源码学习(二)$mount() 后的做的事(1)

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

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

  跳过这个复杂的函数。

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

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

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

  后来又重写了$mount 方法:

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

(二)mountComponent () 函数

组件安装

 function mountComponent(vm, el, hydrating) {
vm.$el = el;
if (!vm.$options.render) {
//如果不存咋,则创建一个空的虚拟节点
vm.$options.render = createEmptyVNode;
}
callHook(vm, 'beforeMount'); var updateComponent;
if ("development" !== 'production' && config.performance && mark) {
//此处另一种 updateComponent = 。。。。
} else {
updateComponent = function () {
vm._update(vm._render(), hydrating); //渲染DOM
};
}
//noop 空函数,
vm._watcher = new Watcher(vm, updateComponent, noop); //生成中间件 _watcher
hydrating = false; // $vnode不存在,,则手动安装实例,自启动
// mounted is called for render-created child components in its inserted hook
if (vm.$vnode == null) {
vm._isMounted = true;
callHook(vm, 'mounted');
}
return vm //调用 实例加载钩子函数,返回vue实例
}

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

(3)Watcher对象

     1、构造函数

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

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

   Vue源码学习(二)$mount() 后的做的事(1)

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

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

2、Watcher.prototype.get()

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

 Watcher.prototype.get = function get() {
pushTarget(this);
var value;
var vm = this.vm;
try {
//初始化时 最终 调用我们传入的 updateComponent
// vm._update(vm._render(), hydrating)
value = this.getter.call(vm, vm);
} catch (e) {
} finally {
if (this.deep) {
traverse(value);
}
popTarget();
this.cleanupDeps();
}
return value
};

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

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

 Vue源码学习(二)$mount() 后的做的事(1)

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

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

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

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

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

  function defineReactive$$(obj, key, val, customSetter, shallow) {
var dep = new Dep();//依赖管理
/* 此时obj 是带有__ob__属性的对象,key是msg */
var property = Object.getOwnPropertyDescriptor(obj, key);//返回键描述信息
if (property && property.configurable === false) {
//不可以修改直接返回
return
} var getter = property && property.get;
var setter = property && property.set; var childOb = !shallow && observe(val);
Object.defineProperty(obj, key, {
enumerable: true,
configurable: true,
get: function reactiveGetter() {
var value = getter ? getter.call(obj) : val;
if (Dep.target) {
dep.depend();
if (childOb) {
childOb.dep.depend();
if (Array.isArray(value)) {
dependArray(value);
}
}
}
return value
},
set: function reactiveSetter(newVal) {
var value = getter ? getter.call(obj) : val; //获取当前值,是前一个值
if (newVal === value || (newVal !== newVal && value !== value)) {
//值没有发生变化,不再做任何处理
return
}
/* eslint-enable no-self-compare */
if ("development" !== 'production' && customSetter) {
customSetter();
}
if (setter) {
setter.call(obj, newVal);//调用默认setter方法或将新值赋给当前值
} else {
val = newVal;
}
childOb = !shallow && observe(newVal);
dep.notify();//赋值后通知依赖变化
}
});
}

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 源码学习(1)

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

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

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

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

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

  8. Dubbo源码学习(二)

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

  9. python 协程库gevent学习--gevent源码学习(二)

    在进行gevent源码学习一分析之后,我还对两个比较核心的问题抱有疑问: 1. gevent.Greenlet.join()以及他的list版本joinall()的原理和使用. 2. 关于在使用mon ...

  10. Vue源码学习(一)———数据双向绑定 Observer

    从最简单的案例,来学习Vue.js源码. <body> <div id='app'> <input type="text" v-model=&quot ...

随机推荐

  1. 解析Exception和C&num;处理Exception的常用方法总结

    在.NET中,异常是指成员没有完成它的名称宣称可以完成的行动.在异常的机制中,异常和某件事情的发生频率无关. 异常处理四要素包括:一个表示异常详细信息的类类型:一个向调用者引发异常类实例的成员:调用者 ...

  2. &lbrack;转载&rsqb;给IT人员支招:如何跟业务部门谈需求分析?

    一提跟业务人员做“需求分析”,许多IT人员立刻就头大了,要么不在同一个“频道”讲话,要么“变来变去,定不下来”.如何跟业务部门谈需求分析呢,我们带着这个问题,与聚冠因尚的咨询顾问杨春波展开了讨论. 1 ...

  3. 如何激活一个window&sol;dialog &amp&semi;&amp&semi; 不能直接对Dialog Box使用SetFocus

    问题,症状: 程序的主窗口CMainWnd创建了一个modal dialog,希望这个dialog能接收WM_KEYDOWN消息,但是需要点一下这个dialog窗口它才能接收到(我嫌麻烦),而且我发现 ...

  4. 161031、java&period;util&period;StringTokenizer使用及源码

    import java.util.StringTokenizer; public class TestStringTokenizer { public static void main(String[ ...

  5. ADO&period;NET 快速入门(十四):使用 SQL Server 检索数据

    SqlDataReader 类提供了一种从数据源读取数据记录只进流的方法.如果想使用 OLE DB 接口的数据库或者 SQL Server7.0 之前的版本,请参考文章:使用 OLE DB 检索数据. ...

  6. JavaScript中的一些细节

    1.设置id / class等属性 用 setAttribute 设置一些常规属性如 id ,className 的时候经常不起作用,只能用 object.id = value 这样来设置 news_ ...

  7. F - 蜘蛛牌(深度搜索)

    Problem Description 蜘蛛牌是windows xp操作系统自带的一款纸牌游戏,游戏规则是这样的:只能将牌拖到比她大一的牌上面(A最小,K最大),如果拖动的牌上有按顺序排好的牌时,那么 ...

  8. git push 小结

    $ git push ssh://git@dev.lemote.com/rt4ls.git master // 把本地仓库提交到远程仓库的master分支中 $ git remote add orig ...

  9. AbtestingGateway 分流策略添加

    目录结构分布 我们从GitHub上把它下载后解压出来,有以下5个目录,分别是: admin 管理模块,对策略增删改查等功能 diversion 主模块吧,看源码是匹配redis存储的key doc 文 ...

  10. 小程序模板中data传值有无&period;&period;&period;

    A:<template is="gemSelectColor" data="{{optionData}}" />B:<template is= ...