Vue组件是怎样挂载的
我们先来关注一下$mount
是实现什么功能的吧:
我们打开源码路径core/instance/init.js
:
export function initMixin (Vue: Class<Component>) {......initLifecycle(vm)// 事件监听初始化initEvents(vm)initRender(vm)callHook(vm, 'beforeCreate')initInjections(vm) // resolve injections before data/props//初始化vm状态 prop/data/computed/watch完成初始化initState(vm)initProvide(vm) // resolve provide after data/propscallHook(vm, 'created')......// 配置项里有el属性, 则会挂载到真实DOM上, 完成视图的渲染// 这里的$mount方法,本质上调用了core/instance/liftcycle.js中的mountComponent方法if (vm.$options.el) {vm.$mount(vm.$options.el)}}
}
在这里我们怎么理解这个挂载状态呢?先来看Vue官方给的一段描述
- 如果
Vue
实例在实例化时没有收到el
选项,则它处于“未挂载”
状态,没有关联的DOM
元素。 - 可以使用
vm.$mount()
手动地挂载一个未挂载的实例。 - 如果没有提供
elementOrSelector
参数,模板将被渲染为文档之外的的元素。 - 并且你必须使用
原生DOM API
把它插入文档中。
那我们来看一下$mount内部机制吧:
* 缓存之前的$mount的方法以便后面返回实例,*/
const mount = Vue.prototype.$mount
/** * 手动地挂载一个未挂载的根元素,并返回实例自身(Vue实例) */
Vue.prototype.$mount = function (el?: string | Element, hydrating?: boolean
): Component {el = el && query(el)/* istanbul ignore if *//** * 挂载对象不能为body和html标签 */if (el === document.body || el === document.documentElement) {process.env.NODE_ENV !== 'production' && warn(`Do not mount Vue to <html> or <body> - mount to normal elements instead.`)return this}const options = this.$options// resolve template/el and convert to render function/** * 判断$options是否有render方法 * 有:判断是String还是Element,获取他们的innerHTMl * 无:在实例Vue时候在vnode里创建一个创建一个空的注释节点 见方法createEmptyVNode */if (!options.render) {let template = options.templateif (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)}}/** * 获取的Element的类型 * 详细见 https://developer.mozilla.org/zh-CN/docs/Web/API/Element/outerHTML */} else if (template.nodeType) {template = template.innerHTML} else {if (process.env.NODE_ENV !== 'production') {warn('invalid template option:' + template, this)}return this}} else if (el) {template = getOuterHTML(el)}if (template) {/* istanbul ignore if *//** * 用于监控compile 的性能 */if (process.env.NODE_ENV !== 'production' && config.performance && mark) {mark('compile')}// 如果不存在 render 函数,则会将模板转换成render函数const { render, staticRenderFns } = compileToFunctions(template, {shouldDecodeNewlines,shouldDecodeNewlinesForHref,delimiters: options.delimiters,comments: options.comments}, this)options.render = renderoptions.staticRenderFns = staticRenderFns/* istanbul ignore if *//** * 用于监控compile 的性能 */if (process.env.NODE_ENV !== 'production' && config.performance && mark) {mark('compile end')measure(`vue ${this._name} compile`, 'compile', 'compile end')}}}return mount.call(this, el, hydrating)
}
而$mount
实现的是mountComponent
函数功能
// public mount method
Vue.prototype.$mount = function (el?: string | Element, hydrating?: boolean
): Component {el = el && inBrowser ? query(el) : undefinedreturn mountComponent(this, el, hydrating)
}
那么我们再去找一下mountComponent
函数吧:
export function mountComponent (vm: Component,el: ?Element,hydrating?: boolean
): Component {vm.$el = el// 如果不存在render函数,则直接创建一个空的VNode节点if (!vm.$options.render) {vm.$options.render = createEmptyVNodeif (process.env.NODE_ENV !== 'production') {/* istanbul ignore if */if ((vm.$options.template && vm.$options.template.charAt(0) !== '#') ||vm.$options.el || el) {warn('You are using the runtime-only build of Vue where the template ' +'compiler is not available. Either pre-compile the templates into ' +'render functions, or use the compiler-included build.',vm)} else {warn('Failed to mount component: template or render function not defined.',vm)}}}// 检测完render后,开始调用beforeMount声明周期callHook(vm, 'beforeMount')let updateComponent/* istanbul ignore if */if (process.env.NODE_ENV !== 'production' && config.performance && mark) {updateComponent = () => {const name = vm._nameconst id = vm._uidconst startTag = `vue-perf-start:${id}`const endTag = `vue-perf-end:${id}`mark(startTag)const vnode = vm._render()mark(endTag)measure(`vue ${name} render`, startTag, endTag)mark(startTag)vm._update(vnode, hydrating)mark(endTag)measure(`vue ${name} patch`, startTag, endTag)}} else {updateComponent = () => {// 这里是上面所说的观察者,这里注意第二个expOrFn参数是一个函数// 会在new Watcher的时候通过get方法执行一次// 也就是会触发第一次Dom的更新vm._update(vm._render(), hydrating)}}vm._watcher = new Watcher(vm, updateComponent, noop, null, true /* isRenderWatcher */)hydrating = false//触发$mount函数if (vm.$vnode == null) {vm._isMounted = truecallHook(vm, 'mounted')}return vm
}
总结来说就是:
- 执行
vm._watcher = new Watcher(vm, updateComponent, noop)
。 - 触发
Watcher
里面的get
方法,设置Dep.target = watcher
。 - 执行
updateComponent
。
这个过程中,会去读取我们绑定的数据,由于之前我们通过Observer
进行了数据劫持,这样会触发数据的get
方法。此时会将watcher添加到 对应的dep中。当有数据更新时,通过dep.notify()
去通知到Watcher
,然后执行Watcher
中的update
方法。此时又会去重新执行updateComponent
,至此完成对视图的重新渲染。
我们着重关注一下vm._update(vm._render(), hydrating)
:
...let vnodetry {vnode = render.call(vm._renderProxy, vm.$createElement)} catch (e) {handleError(e, vm, `render`)// return error render result,// or previous vnode to prevent render error causing blank component/* istanbul ignore else */if (process.env.NODE_ENV !== 'production') {if (vm.$options.renderError) {try {vnode = vm.$options.renderError.call(vm._renderProxy, vm.$createElement, e)} catch (e) {handleError(e, vm, `renderError`)vnode = vm._vnode}} else {vnode = vm._vnode}} else {vnode = vm._vnode}}
我们看到有俩个方法vm._renderProxy
代理vm
,要来检测render
是否用了vm
上没有的属性与方法,用来报错,vm.$createElement
则是创建VNode
:
参考 前端进阶面试题详细解答
render: function (createElement) {return createElement('h1', '标题')
}
数据我们是知道怎么更新的,那么组件tamplate
到真实dom
是怎么更新的呢?
- 解析
tamplate
生成字符串 render Function
处理字符串生成VNode
patch diff
算法处理VNode
相关文章:
Vue组件是怎样挂载的
我们先来关注一下$mount是实现什么功能的吧: 我们打开源码路径core/instance/init.js: export function initMixin (Vue: Class<Component>) {......initLifecycle(vm)// 事件监听初始化initEvents(vm)initRender(vm)callHook(vm, beforeCreate)initInject…...
gcc: 编译选项:-fdelete-null-pointer-checks、-fno-delete-null-pointer-checks
文章目录 说明实例:Linux 里的使用chatGPT说明 这个说明写的有些理解不了,可能还是不太理解(有未知的东西在里面?)。但是从这个编译选项的命名上来看还是非常明确,就是删除不必要的空指针检查。使用时要小心了,这个优化超出了编译的界限! -fdelete-null-pointer-check…...
周赛334(前缀和、贪心+双指针、Dijkstra求最短路径、二分答案)
文章目录[6369. 左右元素和的差值](https://leetcode.cn/problems/left-and-right-sum-differences/)前缀和[6368. 找出字符串的可整除数组](https://leetcode.cn/problems/find-the-divisibility-array-of-a-string/)超长整数如何取余?[6367. 求出最多标记下标](ht…...
imx6ull——I2C驱动
I2C基本介绍 SCL 为高电平,SDA 出现下降沿:起始位 SCL 位高电平,SDA出现上升沿:停止位 主机——从机地址(ack)——寄存器地址(ack)——数据(ack) 重点:先是写,…...
Spring Cache的基本使用与分析
概述 使用 Spring Cache 可以极大的简化我们对数据的缓存,并且它封装了多种缓存,本文基于 redis 来说明。 基本使用 1、所需依赖 <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-…...
【安全知识】——端口复用隐藏后门
作者名:白昼安全主页面链接: 主页传送门创作初心: 以后赚大钱座右铭: 不要让时代的悲哀成为你的悲哀专研方向: web安全,后渗透技术每日鸡汤: 精彩的人生是在有限的生命中实现无限价值端口复用是…...
Tina_Linux量产测试使用指南_new
OpenRemoved_Tina_Linux_量产测试_使用指南_new 1 概述 文档主要描述如何配置tinatest 并搭建量产测试环境。 1.1 编写目的 • 介绍量产配置方法; • 介绍量产测试环境搭建流程; • 介绍如何使用dragonMAT 软件; • 方便开发人员按照说明…...
STC32单片机 普通 I/O 口中断功能介绍和使用
STC32单片机 普通 I/O 口中断功能和使用✨STC32单片机普通 I/O 口中断,不是传统外部中断. 🔖手册上描述:STC32G 系列支持所有的 I/O 中断,且支持 4 种中断模式:下降沿中断、上升沿中断、低电平中断、高电平中断。每组 …...
计算机学生如何找到第一份实习?
作为一名计算机专业的学生,找到第一份实习是非常重要的一步,它不仅可以帮助你更好地了解行业,增加实践经验,还可以为即将到来的校招提供有力支持。计算机专业的校招,每年都在变得越来越卷。5年前,可能你只要…...
《Python机器学习》基础代码
1,要学习Python机器学习,第一步就是读入数据,这里我们以读入excel的数据为例,利用jupyter notebook来编码,具体教程看这个视频 推荐先上传到jupyter notebook,再用名字.xlsx来导入 Jupyter notebook导入Excel数据的两种方法介绍_哔哩哔哩_bilibili 2,…...
【前端】JS异步加载
文章目录为什么要异步加载如何实现异步加载参考为什么要异步加载 两个原因其实是一个意思。 原因1: JS是单线程的语言,它会同步的执行代码,从上往下执行 但是,一旦网络不好,或要加载的js文件过大的话,会…...
【MySQL】SQL语言的五个部分
DQL 数据查询语言(Data Query Language,DQL):DQL主要用于数据的查询,其基本结构是使用SELECT子句,FROM子句和WHERE子句的组合来查询一条或多条数据。 DML 数据操作语言(Data Manipulation La…...
详细的IO面试题汇总
IO 流简介 IO 即 Input/Output,输入和输出。数据输入到计算机内存的过程即输入,反之输出到外部存储(比如数据库,文件,远程主机)的过程即输出。数据传输过程类似于水流,因此称为 IO 流。IO 流在…...
在Linux终端管理你的密码!
大家好,我是良许。 现在是互联网时代,我们每天都要跟各种 APP 、网站打交道,而这些东西基本上都需要注册才可以使用。 但是账号一多,我们自己都经常记不清对应的密码了。有些小伙伴就一把梭,所有的账号密码都是一样。…...
【设计模式】策略模式在Java工程中应用
在之前的文章中,曾经给大家介绍过策略模式:【设计模式】策略模式,在该篇文章中,我们曾很清楚的说到,策略模式主要解决的问题是:在有多种算法相似的情况下,解决使用 if...else 所带来的复杂和难以…...
Linux驱动开发工程师需要掌握哪些技能?
一、前言 Linux驱动开发是一项高度技术性的工作,需要深厚的编程技能和对计算机硬件的深入理解。随着物联网、人工智能等领域的快速发展,Linux驱动开发工程师的需求日益增加。在这篇文章中,我将为您介绍一条Linux驱动开发工程师的学习路线&am…...
【人脸识别】FROM:提升遮挡状态下的人脸识别效果
论文题目:《End2End Occluded Face Recognition by Masking Corrupted Features》 论文地址:https://arxiv.org/pdf/2108.09468v3.pdf 代码地址:https://github.com/haibo-qiu/from 1.前言 人脸识别技术已经取得了显著的进展,主要…...
浏览器缓存
什么是缓存? 当第一次访问网站的时候,比如www.baidu.com,电脑会图片,文件等下载下来,当第二次访问网站的时候,网站就会直接被加载出来. 缓存的好处? 减轻服务器压力,减少请求的放松.提高性能,在本地打开资源肯定比在服务器上获取要快减少宽带的消耗,当我们使用缓存时,只会…...
【软考 系统架构设计师】论文范文③ 论数据访问层设计技术及其应用
>>回到总目录<< 文章目录 论数据访问层设计技术及其应用范文摘要正文论数据访问层设计技术及其应用 在信息系统的开发与建设中,分层设计是一种常见的架构设计方法,区分层次的目的是为了实现“高内聚低耦合”的思想。分层设计能有效简化系统复杂性,使设计结构清…...
802.11 MCS 的最低SNR分析
常常看到这样的表格: 那么这个SNR如何而来? 看看RSSI和SNR的关系,它们之间隔了一个noise floor。从表格看得出,这个底噪在-80~-90之间。 而SNR的核心,也有类似的原因,它和BER有关。...
用于C++的对象关系映射库—YB.ORM
1 介绍YB.ORM YB.ORM 旨在简化与关系数据库交互的 C 应用程序的开发。 对象关系映射器(ORM) 通过将数据库表映射到类并将表行映射到应用程序中的对象来工作,这种方法可能不是对每个数据库应用程序都是最佳的,但它被证明在需要复杂逻辑和事务处理的应用程…...
Cesium 100K数据加载 支持弹窗 动态更改位置
前言:今天总结关于point、label、billboard海量数据加载。后续会研究下大量model加载以及大bim(几百G上T)模型记载 海量点加载 弹窗 加载点位时,不加载弹窗。点击点位时在加载弹窗,及有效的减少加载量,优化性能。 const handler …...
MySQL管理表
在创建表时需要提前了解mysql里面的数据类型 常见的数据类型 创建表 创建表方式1: 格式: CREATE TABLE [IF NOT EXISTS] 表名( 字段1, 数据类型 [约束条件] [默认值], 字段2, 数据类型 [约束条件] [默认值], 字段3, 数据类型 [约束条件] [默认值], ………...
【Java 面试合集】打印一个int整数的32位表示
打印一个int整数的32位表示 1. 概述 嗨,大家好【Java 面试合集】又来了,今天给大家分享的主题是打印一个int整数的32位表示. 2. 32位分析 2.1 为什么是32位呢 不知道看到这篇文章的各位是否都知道,一个int类型的表示方式就是32位呢&#x…...
这样在管理后台里实现 403 页面实在是太优雅了
前言403 页面通常表示无权限访问,与 404 页面代表着不同含义。而大部分管理后台框架仅提供了 404 页面的支持,但却忽略了对 403 页面的处理,有的框架虽然也有对 403 页面的处理,但处理效果却不尽人意。那怎么样的 403 页面才是即好…...
c++提高篇——STL常用算法
STL常用算法一、常用遍历算法一、for_each 遍历容器二、transform 搬运容器到另一个容器中二、常用查找算法一、find二、find_if三、adjacent_find四、binary_search五、count六、count_if三、常用排序算法一、sort二、random_shuffle三、 merage四、reverse四、常用拷贝和替换…...
Materials - DistanceField Nodes
以前的相关笔记,归档发布;距离场相关节点:DistanceToNearestSurface节点:求出传入的Position位置到最近的面的距离并输出,在没有Position输入的时候,默认值会直接使用World Position:Position的…...
【ARMv8 编程】ARMv8 指令集介绍
ARMv8 架构中引入的最重要的变化之一是增加了 64 位指令集。该指令集补充了现有的 32 位指令集架构。这种增加提供了对 64 位宽整数寄存器和数据操作的访问,以及使用 64 位长度的内存指针的能力。新指令被称为 A64,以 AArch64 执行状态执行。ARMv8 还包括…...
大数据之Phoenix基本介绍
文章目录前言一、Phoenix简介二、Phoenix入门(一)创建表语法(二)查看表信息(三)删除表(四)大小写问题前言 #博学谷IT学习技术支持# 上篇文章介绍了Phoenix环境搭建,点击…...
算法leetcode|38. 外观数列(多语言实现)
文章目录38. 外观数列:样例 1:样例 2:提示:分析:题解:rustgocpythonjava38. 外观数列: 给定一个正整数 n ,输出外观数列的第 n 项。 「外观数列」是一个整数序列,从数字…...
本地旅游网站模版/苏州百度推广公司地址
我知道我迟早是要踏上了后台测试之路的,只是没想到来的这么突然。新接手了一个项目,在第一版发出后,产品需要做运营活动拉量,因为我担心突然的流量涌入是否会对后台造成压力呢?因此决定做一下压测: 下面就一…...
网站建设与设计开题报告/郑州seo建站
为了避免全局变量泛滥导致冲突,最简单有效的办法是用匿名函数将脚本包起来,让变量的作用域控制在函数之内。 转载于:https://www.cnblogs.com/wangxuchun/p/3761181.html...
网站编辑器介绍/谷歌seo视频教程
目录1、前言2、主从复制好处3、服务器准备4、环境搭建4.1、创建集群工作目录4.2、搭建单机环境4.3、集群配置4.4、复制实例4.5、修改其他实例配置文件4.6、创建批量启动/关闭脚本4.7、创建集群5、整合SpringBoot6、删除、新增节点6.1、删除从节点6.2、新增从节点6.3、删除主节点…...
网站上面的彩票快3怎么做/在线外链发布工具
工作步骤:下载内核源码和相关的软件包;把ipvs补丁Patch到内核源码中;重新编译支持ipvs的内核;启用新内核;安装ipvs管理工具ipvsadm;配置LVS,构建负载均衡集群。 (1) 下载安装所需组件: 标准内…...
上海建设单位工程备案网站/hao123网址导航
从Theano到Lasagne:基于Python的深度学习的框架和库 摘要:最近,深度神经网络以“Deep Dreams”形式在网站中如雨后春笋般出现,或是像谷歌研究原创论文中描述的那样:Inceptionism。在这篇文章中,我们将讨论几…...
黔江城乡建设委员会的网站/网站seo推广招聘
data与el的2种写法 1.el有2种写法 (1).new Vue时候配置el属性。 new Vue({el:#root, //第一种写法data:{name:尚硅谷}})(2).先创建Vue实例,随后再通过vm.$mount(#root)指定el的值。 const v new Vue({data:{name:尚硅谷} })console.log(v) v.$mount(#root) //第…...