Vue源码学习(二)$mount() 后的做的事(1)
Vue实例初始化完成后,启动加载($mount)模块数据。
(一)Vue$3.protype.$mount
标红的函数 compileToFunctions 过于复杂,主要是生AST 树,返回的 ref 如下:
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实例。
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(),代码如下
这里 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)的更多相关文章
- Vue源码学习1——Vue构造函数
Vue源码学习1--Vue构造函数 这是我第一次正式阅读大型框架源码,刚开始的时候完全不知道该如何入手.Vue源码clone下来之后这么多文件夹,Vue的这么多方法和概念都在哪,完全没有头绪.现在也只 ...
- Vue源码学习三 ———— Vue构造函数包装
Vue源码学习二 是对Vue的原型对象的包装,最后从Vue的出生文件导出了 Vue这个构造函数 来到 src/core/index.js 代码是: import Vue from './instanc ...
- Vue源码学习二 ———— Vue原型对象包装
Vue原型对象的包装 在Vue官网直接通过 script 标签导入的 Vue包是 umd模块的形式.在使用前都通过 new Vue({}).记录一下 Vue构造函数的包装. 在 src/core/in ...
- 最新 Vue 源码学习笔记
最新 Vue 源码学习笔记 v2.x.x & v3.x.x 框架架构 核心算法 设计模式 编码风格 项目结构 为什么出现 解决了什么问题 有哪些应用场景 v2.x.x & v3.x.x ...
- 【Vue源码学习】依赖收集
前面我们学习了vue的响应式原理,我们知道了vue2底层是通过Object.defineProperty来实现数据响应式的,但是单有这个还不够,我们在data中定义的数据可能没有用于模版渲染,修改这些 ...
- Vue 源码学习(1)
概述 我在闲暇时间学习了一下 Vue 的源码,有一些心得,现在把它们分享给大家. 这个分享只是 Vue源码系列 的第一篇,主要讲述了如下内容: 寻找入口文件 在打包的过程中 Vue 发生了什么变化 在 ...
- 【Vue源码学习】响应式原理探秘
最近准备开启Vue的源码学习,并且每一个Vue的重要知识点都会记录下来.我们知道Vue的核心理念是数据驱动视图,所有操作都只需要在数据层做处理,不必关心视图层的操作.这里先来学习Vue的响应式原理,V ...
- Vue源码学习(一):调试环境搭建
最近开始学习Vue源码,第一步就是要把调试环境搭好,这个过程遇到小坑着实费了点功夫,在这里记下来 一.调试环境搭建过程 1.安装node.js,具体不展开 2.下载vue项目源码,git或svn等均可 ...
- VUE 源码学习01 源码入口
VUE[version:2.4.1] Vue项目做了不少,最近在学习设计模式与Vue源码,记录一下自己的脚印!共勉!注:此处源码学习方式为先了解其大模块,从宏观再去到微观学习,以免一开始就研究细节然后 ...
- Dubbo源码学习(二)
@Adaptive注解 在上一篇ExtensionLoader的博客中记录了,有两种扩展点,一种是普通的扩展实现,另一种就是自适应的扩展点,即@Adaptive注解的实现类. @Documented ...
随机推荐
- YAML快速入门
https://www.jianshu.com/p/97222440cd08 我们学习Java,都是先介绍properties文件,使用properties文件配合Properties对象能够很方便的 ...
- (转)K-近邻算法(KNN)
K-近邻算法(KNN)概述 KNN是通过测量不同特征值之间的距离进行分类.它的思路是:如果一个样本在特征空间中的k个最相似(即特征空间中最邻近)的样本中的大多数属于某一个类别,则该样本也属于这个类别 ...
- 记录Redis使用中遇到的两个问题(原子性及数据完整性)
1.使用Redis作为分布式锁的原子性问题 原方案: ① SETNX $LOCK_BUSI_KEY $REQ_ID ② EXPIRE $LOCK_BUSI_KEY $LOCK_TIME 问题: 使用S ...
- 高性能 TCP & HTTP 通信框架 HP-Socket v4.3.1
HP-Socket 是一套通用的高性能 TCP/UDP/HTTP 通信框架,包含服务端组件.客户端组件和 Agent 组件,广泛适用于各种不同应用场景的 TCP/UDP/HTTP 通信系统,提供 C/ ...
- ubuntu下多版本OpenCV的共存与使用
首先,OpenCV历史版本下载:https://www.opencv.org/releases.html 一.把不同版本的OpenCV安装在不同位置 下载好OpenCV源码,在安装之前打开CMakeL ...
- 微服务架构基础之Service Mesh
ServiceMesh(服务网格) 概念在社区里头非常火,有人提出 2018 年是 ServiceMesh 年,还有人提出 ServiceMesh 是下一代的微服务架构基础. 那么到底什么是 Serv ...
- 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 ...
- ssm注入失败
今天做ssm整合时候,创建bean/注入一直出错,检查几遍没发现问题,后来发现犯了个低级错误,mapper.xml的<mapper namespace="XXXXX" > ...
- Split CSV/TXT file
void Main(){ var path = @"c:\sourceGit\speciesLatLon.txt"; var inputLines = File.ReadAllLi ...
- url跳转漏洞(1)
转载 https://landgrey.me/open-redirect-bypass/ 0x00:漏洞场景 URL跳转漏洞的出现场景还是很杂的,出现漏洞的原因大概有以下5个: 1. 写代码时没有考虑 ...