当前位置: 首页 > 编程日记 > 正文

vue实例没有挂载到html上,vue 源码学习 - 实例挂载

前言

在学习vue源码之前需要先了解源码目录设计(了解各个模块的功能)丶Flow语法。

src

├── compiler # 把模板解析成 ast 语法树,ast 语法树优化,代码生成等功能。

├── core # 核心代码 Vue.js 的灵魂

├── platforms # 不同平台的支持 web 和 weex

├── server # 服务端渲染这部分代码是跑在服务端的 Node.js

├── sfc # .vue 文件解析

├── shared # 工具方法

复制代码

flow语法可以参照 v-model源码学习中提到的flow语法介绍,以及到官网了解更多。

vue 实例化

vue 本质上就是一个用 Function 实现的 Class,然后它的原型 prototype 以及它本身都扩展了一系列的方法和属性

vue 的定义

在 src/core/instance/index.js 中

import { initMixin } from './init'

import { stateMixin } from './state'

import { renderMixin } from './render'

import { eventsMixin } from './events'

import { lifecycleMixin } from './lifecycle'

import { warn } from '../util/index'

function Vue (options) {

if (process.env.NODE_ENV !== 'production' &&

!(this instanceof Vue)

) {

warn('Vue is a constructor and should be called with the `new` keyword')

}

this._init(options)

}

initMixin(Vue)

stateMixin(Vue)

eventsMixin(Vue)

lifecycleMixin(Vue)

renderMixin(Vue)

export default Vue

复制代码

通过源码我们可以看到,它实际上就是一个构造函数。我们往后看这里有很多 xxxMixin 的函数调用,并把 Vue 当参数传入,它们的功能都是给 Vue 的 prototype 上扩展一些方法。

阶段

首先通过new Vue实例化,过程可以参考之前写的vue 生命周期梳理

vue 实例挂载的实现

Vue中是通过$mount实例方法去挂载vm,$mount方法再多个文件中都有定义,和平台,构建方式相关。 首先来看 src/platform/web/entry-runtime-with-compiler.js文件中

const mount = Vue.prototype.$mount

Vue.prototype.$mount = function (

el?: string | Element,

hydrating?: boolean

): Component {

el = el && query(el)

// A-> ..... 代表后面省略的代码从A-> 处接下去

}

复制代码

1.这段代码首先缓存了原型上的$mount 方法,再重新定义该方法

为了对比前后方法的差别,我们可以先看

compiler 版本的 $mount

a710d27ce4ada4e5fb52d82c33093d1f.png

2. $mount方法支持传入两个参数,第一个是el,它表示挂载的元素,可以是字符串,可以是DOM对象,会调用query方法转换成DOM对象,在浏览器环境下我们不需要传第二个参数,它是一个可选参数。

接下来继续看后面的代码

//

if (el === document.body || el === document.documentElement) {

process.env.NODE_ENV !== 'production' && warn(

`Do not mount Vue to or

- mount to normal elements instead.`

)

return this

}

const options = this.$options

// A-> ..... 代表后面省略的代码从A-> 处接下去

复制代码

首先对 el 做了限制,Vue 不能挂载在 body、html 这样的根节点上。如果是其中一个则返回this。this就是vue实例本身00ffcf091ed972237d8a958add41bec5.png

定义option对象(new Vue中传入的数据)

//

if (!options.render) {

let template = options.template

if (template) {

// B-> ..... 代表后面省略的代码从B-> 处接下去

}else if(el){

// C-> ..... 代表后面省略的代码从C-> 处接下去

}

if (template) {

// D-> ..... 代表后面省略的代码从D-> 处接下去

}

return mount.call(this, el, hydrating)

}

复制代码判断有没有定义render方法,没有则会把el或者template字符串转换成render方法。在 Vue 2.0 版本中,所有 Vue 的组件的渲染最终都需要 render 方法

//

if(template){

if (typeof template === 'string') {

if (template.charAt(0) === '#') {

template = idToTemplate(template)

/* istanbul ignore if */

if (process.env.NODE_ENV !== 'production' && !template) {

warn(

`Template element not found or is empty: ${options.template}`,

this

)

}

}else if (template.nodeType) {

template = template.innerHTML

}

}

复制代码判断template 是否为字符串,取字符串的第一位判断是否是# 如果是#开头代表节点字符串,并调用idToTemplate方法如下

const idToTemplate = cached(id => {

const el = query(id)

return el && el.innerHTML

})

复制代码

接受一个参数,对这个参数进行query方法,前面提到query是将字符串转化成DOM,并且返回DOM的innerHTML

//

template = getOuterHTML(el)

复制代码

如果没有render和template的情况下,使用getOuterHTML方法重新定义template

function getOuterHTML (el: Element): string {

if (el.outerHTML) {

return el.outerHTML

} else {

const container = document.createElement('div')

container.appendChild(el.cloneNode(true))

return container.innerHTML

}

}

复制代码挂在DOM元素的HTML会被提取出来用作模板

be5ef99e5da3e9bcaadae7adb5fa9642.png

总结 : render函数优先级最高,template和el次之

模板类型

render : 类型function 接收一个 createElement 方法作为第一个参数用来创建 VNode

render: function (createElement) {

return createElement(

'h' + this.level, // 标签名称

this.$slots.default // 子元素数组

)

},

复制代码template:类型string 一个字符串模板作为 Vue 实例的标识使用。模板将会 替换 挂载的元素。

el:类型string | HTMLElement 提供一个在页面上已存在的 DOM 元素作为 Vue 实例的挂载目标。可以是 CSS 选择器,也可以是一个 HTMLElement 实例

runtime only 版本的$mount

Vue.prototype.$mount = function (

el?: string | Element,

hydrating?: boolean

): Component {

el = el && inBrowser ? query(el) : undefined

return mountComponent(this, el, hydrating)

}

复制代码

开始和compiler版本的$mount 实现相同,只不过多加了一个inBrowser判断是否在浏览器环境下。

$mount 方法实际上会去调用 mountComponent 方法,这个方法定义在 src/core/instance/lifecycle.js 文件中

export function mountComponent (

vm: Component,

el: ?Element,

hydrating?: boolean

): Component {

vm.$el = el

if (!vm.$options.render) {

vm.$options.render = createEmptyVNode

}

callHook(vm, 'beforeMount')

// A-> ..... 代表后面省略的代码从A-> 处接下去

}

复制代码mountComponent接收到Vue.prototype.$mount方法中vue实例对象,和el字符串(经过query处理已经转成DOM)

更新vm实例上的$el

判断vm上有无render模板,如果没有创建一个空的虚拟VNode

插入beforeMount钩子

//

let updateComponent

if (process.env.NODE_ENV !== 'production' && config.performance && mark) {

}else{

updateComponent = () => {

vm._update(vm._render(), hydrating)

}

}

vm._watcher = new Watcher(vm, updateComponent, noop)

// A-> ..... 代表后面省略的代码从A-> 处接下去

复制代码mountComponent 核心就是先调用vm._render方法先生成虚拟 Node 将 vm._update方法作为返回值赋值给updateComponent

实例化Watcher构造函数,将updateComponent作为回调函数,也就是说在实例化Watcher后最终调用vm._update 更新 DOM。

watcher的作用

实例化的过程后执行回调,将调用vm._update 更新 DOM。

vm 实例中的监测的数据发生变化的时候执行回调函数实现更新DOM

//

hydrating = false

if (vm.$vnode == null) {

vm._isMounted = true

callHook(vm, 'mounted')

}

return vm

复制代码

这里vm.$vnode的值是什么,文件定义在src/core/instance/render.js 中,这里只关注vm.$vnode所以贴出相关代码

export function renderMixin (Vue: Class) {

Vue.prototype._render = function (): VNode {

const vm: Component = this

const { render, _parentVnode } = vm.$options

vm.$vnode = _parentVnode

}

}

复制代码

renderMixin函数接收Vue实例参数,在vue原型上的内部_render方法需要返回一个VNode,并且通过结构赋值的方法取出实例中$options的属性和方法。

我们来看看vm.$options对象具体有些什么

82e845bb54990140256da6c70ad73a20.png

对象中有render函数,但是还未定义_parentVnode。可以知道vm.$vnode 表示 Vue 实例的父虚拟 Node,而且在mountComponent 函数中值还未定义。

由于未定义vm.$vnode值为undefined 所以vm.$vnode==null结果也为真

a1957f237ad6b9aa7ceab5d10a8ab879.png

我们也可以通过生命周期图来理解, VNode render 是发生在beforeUPdate 之后updated之前这个环节

流程 :(1) new Vue ==> (2) init ==> (3) $mount ==> (4) compile ==> (5) render ==> (6) vnode ==> (7) patch ==> (8) DOM

最后设置 vm._isMounted 为 true作为之后判断是否经历了mounted生命周期的条件

总结

判断挂载的节点不能挂载在 body、html 上。

模板优先级render>template>el 并且最终都会转换成render方法

知道mountComponent方法 做了什么,先是调用了vm._render 方法先生成虚拟 Node,然后实例化Watcher 执行它,并监听数据变化,实时更新。

设置vm._isMounted标志,作为判断依据

相关文章:

为何Redis要比Memcached好用(转)

转载链接:http://blog.csdn.net/renfufei/article/details/40598889 GitHub版本地址: https://github.com/cncounter/translation/blob/master/tiemao_2014/Redis_beats_Memcached/Redis_beats_Memcached.md 副标题: Redis是新兴的通用存储系统,而Memcached仍有其适…

2022-2028年中国数字化制造产业研究及前瞻分析报告

【报告类型】产业研究 【报告价格】4500起 【出版时间】即时更新(交付时间约3个工作日) 【发布机构】智研瞻产业研究院 【报告格式】PDF版 本报告介绍了中国数字化制造行业市场行业相关概述、中国数字化制造行业市场行业运行环境、分析了中国数字化…

转载知乎上的一篇:“ 面向对象编程的弊端是什么?”

2019独角兽企业重金招聘Python工程师标准>>> 弊端是,没有人还记得面向对象原本要解决的问题是什么。1、面向对象原本要解决什么(或者说有什么优良特性)似乎很简单,但实际又很不简单:面向对象三要素封装、继…

Windows Azure 如何学习Azure

通过上一篇博文可以得知,Azure其实是个平台,上面跑的服务五花八门,可以相互分开使用,同时也可以相互结合。 那我们应该如何来学习Azure呢? 其实有很多种选择,正所谓条条大路通罗马, 官方的training kit 提…

最全面的Unity游戏开发指南视频教程 第2卷

最全面的Unity游戏开发指南视频教程 第2卷 流派:电子学习| MP4 |视频:h264,1280720 |音频:AAC,44.1 KHz 语言:英语中英文字幕(根据原英文字幕机译更准确)|大小解压后:4.2 GB |时长:9h 24m 含项目文件 Unity游戏开发…

IOS面试题(二)

50. 谈谈对Block 的理解?并写出一个使用Block执行UIVew动画? 答:Block是可以获取其他函数局部变量的匿名函数,其不但方便开发,并且可以大幅提高应用的执行效率(多核心CPU可直接处理Block指令) 1 2 3 4 5 [UIView transitionWithView:self.…

辽宁省计算机专业A类,辽宁省2008年中职升高职招生考试计算机专业综合试题

辽宁省2008年中职升高职招生考试计算机及应用专业综合课试卷第一部分 必答题(200分)一、单项选择题(在每小题的四个备选答案中,选出一个正确的答案。每小题4分,共44分)1、在数据通信中,将模拟信号变换为数字信号的过程称为A 编码 B解码 C解调…

MyBatis的插入后获得主键的方式

需求&#xff1a; 使用MyBatis往MySQL数据库中插入一条记录后&#xff0c;需要返回该条记录的自增主键值。 方法&#xff1a; 在mapper中指定keyProperty属性&#xff0c;示例如下&#xff1a; <insert id"insertUser" useGeneratedKeys"true" keyP…

JAVA 中 13 种锁的实现方式

分布式系统时代,线程并发,资源抢占,慢慢变得很重要。那么常见的锁都有哪些?

String的Intern()方法,详解字符串常量池!

字符串拼接最好使用StringBuilder调用append来拼接。使用加号“+”拼接,会new一个StringBuilder,并且在最后调用toString方法时还会new String()。内存中由于创建了较多的StringBuilder和String对象,还有一方面是内存占用,调用GC还会额外花费时间。所以,字符串拼接直接使用StringBuilder会大大提高性能,尤其是多个字符串拼接。

硬盘盘符双击无法打开,只能右键打开(解决方法)(转载)

开始---运行---cmd&#xff0c;例如D盘&#xff0c;就输入  D: dir /a &#xff08;没有参数A是看不到的&#xff0c;A是显示所有的意思&#xff09; 此时你会发现一个autorun.inf文件   attrib autorun.inf -s -h -r 去掉autorun.inf文件的系统、只读、隐藏属性&#xff0…

Unity 2021创建2D休闲点击器游戏视频教程

Unity 2021创建2D休闲点击器游戏视频教程 Learn how to create a 2D Idle Clicker Game in Unity 2021 了解如何在Unity 2021中创建2D闲置点击器游戏 MP4 |视频:h264&#xff0c;1280720 |音频:AAC&#xff0c;44.1 KHz&#xff0c;2 Ch 语言&#xff1a;英语中英文字幕&…

html实现pdf预览打印机,Pdf操作(HTML转PDF,PDF直接网页连接打印机)

Pdf导出的操作&#xff1a;引用TuesPechkin.dll和TuesPechkin.Wkhtmltox.AnyCPU.dll程序集&#xff0c;新建PDF静态类 PDFConverter&#xff0c;在web.config配置保存dir/// ///pdf转换/// public static classPdfConvert {/// ///staticDeploymentPath/// private static read…

CUDA编程遇到的问题

1、总喜欢在core 代码中&#xff0c;访问device memory。 然后排错很久&#xff01;&#xff01;&#xff01;&#xff01;&#xff01; 2、第一次cudaMalloc() 耗时很久 3、cudaMalloc对于大数据也耗时很久 4、一致内存使用错误&#xff0c;不知道为什么&#xff01;&#xff…

2022-2028年中国数字化档案加工行业市场深度分析及发展策略分析报告

【报告类型】产业研究 【报告价格】4500起 【出版时间】即时更新&#xff08;交付时间约3个工作日&#xff09; 【发布机构】智研瞻产业研究院 【报告格式】PDF版 本报告介绍了中国数字化档案加工行业市场行业相关概述、中国数字化档案加工行业市场行业运行环境、分析了中…

eclipse打开处于无响应状态解决办法

eclipse打开后处于无响应状态&#xff0c;变没有了反映&#xff0c;并且cup占用率为0。应该是非正常关机导致eclipse工作区的文件状态错误导致。 解决方案&#xff1a;在工作区目录中&#xff0c;有一个.metadata目录&#xff0c;里面是工作区及各插件的信息&#xff0c;删除此…

Unity创建在线多人游戏视频教程

Unity创建在线多人游戏视频教程 Learn To Create An Online Multiplayer Game In Unity 学会在Unity中创建在线多人游戏 MP4 |视频:h264&#xff0c;1280720 |音频:AAC&#xff0c;44.1 KHz&#xff0c;2 Ch 语言&#xff1a;英语中英文字幕&#xff08;根据原英文字幕机译更…

《需求分析》读后感之二

项目的目标是系统的业务需求。在很多情况下&#xff0c;涉众可以清晰地表达出系统的业务需求&#xff0c;这时可以通过安排和涉众的面谈来明确项目的动机。但也有很多情况下&#xff0c;涉众无法表达他们的业务需求&#xff0c;或者表达的业务需求不够清晰。因此&#xff0c;要…

统计学 计算机论文,统计学专业论文范文

1实验教学软件选择 目前流行的统计软件有SAS、SPSS、Statistica、EViews、Excel等&#xff0c;但上述软件的特点和功能优势各不相同&#xff0c;所以要根据学生的专业特点和教学要求选用不同的统计软件或者软件组合。但是由于专业统计软...2019-09-061非统计专业统计学教学过程…

JVM年轻代,老年代,永久代详解​​​​​​​

秉承不重复造轮子的原则&#xff0c;查看印象笔记分享连接↓↓↓↓ 传送门&#xff1a;JVM年轻代&#xff0c;老年代&#xff0c;永久代详解 速读摘要 最近被问到了这个问题&#xff0c;解释的不是很清晰&#xff0c;有一些概念略微模糊&#xff0c;在此进行整理和记录&…

html中#include file的使用方法

有两个文件a.htm和b.htm&#xff0c;在同一文件夹下a.htm内容例如以下 <!-- #include file"b.htm" --> b.htm内容例如以下 今天&#xff1a;雨 31 ℃&#xff5e;26 ℃ <br />明天&#xff1a;雷阵雨 33 ℃&#xff5e;27 ℃ 直接在浏览器中打开a&#…

Linux服务之Samba服务篇

Samba服务 桑巴Smb是基于cs架构 作用&#xff1a;用于跨平台进行文件共享 优点&#xff1a;兼容性好&#xff0c;较为安全(具备身份验证&#xff09; 缺点&#xff1a;仅限内网环境使用 应用&#xff1a;一般在办公环境下使用 rz 也是一种可以在Windows和Linux操作系统之间进行…

ue4商城素材 Cyberpunk City / Recife Environment 赛博朋克城市场景

ue4商城素材 Cyberpunk City / Recife Environment 赛博朋克城市场景 ue4商城素材 Cyberpunk City / Recife Environment 赛博朋克城市场景 ue4商城素材 Cyberpunk City / Recife Environment 赛博朋克城市场景 Unreal Engine虚幻游戏引擎素材资源 Unreal Engine Marketplace …

微型计算机系统外文,微型计算机控系统(单片机控制系统) 毕业论文外文翻译.doc...

微型计算机控系统(单片机控制系统) 毕业论文外文翻译英语翻译Microcontroller reset is to make the CPU and other system features are in a defined initial state, and from this state to work, reset PC 0000H, the microcontroller from the first - a unit to take co…

应用于cookie

将封装好的cookie函数 使用好cookie JavaScript代码 var aAdocument.getElementsByTagName(a); //使用var indexgetCookie(page_index);if(index){tab(index);}for(var i0; i<aA.length; i){(function(index){aA[i].onclickfunction(){tab(index); //设置一个cookiese…

2022-2028年中国数字电视产业投资分析及前景预测报告(全卷)

【报告类型】产业研究 【报告价格】4500起 【出版时间】即时更新&#xff08;交付时间约3个工作日&#xff09; 【发布机构】智研瞻产业研究院 【报告格式】PDF版 本报告介绍了中国数字电视行业市场行业相关概述、中国数字电视行业市场行业运行环境、分析了中国数字电视行…

分形之闵可夫斯基(Minkowski)

与上一篇文章分形之正方形折线相似&#xff0c;闵可夫斯基分形也是分形出正方体&#xff0c;不同之处是它分出了两个正方体。 核心代码: static void FractalMinkowski(const Vector3& vStart, const Vector3& vEnd, Vector3* pVertices) {Vector3 vSub vEnd - vStart…

文本框禁用后(readonly=readonly),光标置于文本框中按后退键,页面后退的解决方案...

//处理键盘事件 禁止后退键&#xff08;Backspace&#xff09;密码或单行、多行文本框除外function forbidBackSpace(e){var ev e || window.event;//获取event对象 var obj ev.target || ev.srcElement;//获取事件源 var t obj.type || obj.getAttribute(type);//获取事件源…

最全19000+国外AE模板合集包

最全19000国外AE模板合集包 此套模板 包含整理好的 2015-2021年6月 国外AE模板 19000多个 大小&#xff1a;3500G 模板已编号&#xff0c;含预览视频&#xff0c;方便预览和查找&#xff0c;&#xff08;少数模板无预览&#xff0c;少数模板只含预览图&#xff09; 云桥网络…

北大网络教育计算机作业,北大网络教育(计算机专业)网络基础作业答案.doc

北大网络教育(计算机专业)网络基础作业答案北大网络教育(计算机专业)计算机网络基础作业答案1.从逻辑结构上看&#xff0c;计算机和路由器分别属于资源子网和通信子网。2、 大型广域网常采用的拓扑结构是网络拓扑结构。3.常借用公用传输网络构建的网络类型是广域网。4. 简单地说…