Vue源码系列6------Vue实例的挂载

Vue源码解析-$mount 前言 Vue实例是通过mount方法进行挂载的,上一篇说了new Vue这篇分析一下mount挂载方法。mount的定义在Vue源码中有多处,这是因为Vue需要适配不同的平台以及构建方式,本文这里主要分析一下带compiler的mount实现方式。 找入口 因为是需要适配不同平台,mount方法定义在src/platform/web/entry-runtime-with-compiler.js下,代码如下: const mount = Vue.prototype.$mount Vue.prototype.$ 阅读详情

Vue 中是通过 $mount 实例方法去挂载 vm 的,$mount 方法在多个文件中都有定义,如 src/platform/web/entry-runtime-with-compiler.js、src/platform/web/runtime/index.js、src/platform/weex/runtime/index.js。因为 $mount 这个方法的实现是和平台、构建方式都相关的。接下来我们重点分析带 compiler 版本的 $monut 实现,因为抛开 webpack 的 vue-loader,我们在纯前端浏览器环境分析 Vue 的工作原理,有助于我们对原理理解的深入。


首先,我们来看$mount 实例方法的定义,在 src/platform/web/entry-runtime-with-compiler.js中:

  const options = this.$options
  // resolve template/el and convert to render function
  if (!options.render) {
    let template = options.template
    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
      } 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 */
      if (process.env.NODE_ENV !== 'production' && config.performance && mark) {
        mark('compile')
      }

      const { render, staticRenderFns } = compileToFunctions(template, {
        shouldDecodeNewlines,
        shouldDecodeNewlinesForHref,
        delimiters: options.delimiters,
        comments: options.comments
      }, this)
      options.render = render
      options.staticRenderFns = staticRenderFns

      /* istanbul ignore if */
      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 方法,然后重新定义该方法。第一,它对 el 做了限制,Vue 不能挂载在 body、html 这样的根节点上。接下来的是判断有没有定义render 方法。如果没有定义 render 方法,则会把 el 或者 template 字符串转换成 render 方法。这里我们要牢记,在 Vue 2.X版本中,所有 Vue 的组件的渲染最终都需要 render 方法,无论我们是用单文件 .vue 方式开发组件,还是写了 el 或者 template 属性,最终都会转换成 render 方法,那么这个过程是 Vue 的一个“在线编译”的过程,它是调用 compileToFunctions 方法实现的。最后,调用原先原型上的 $mount 方法挂载。

【小贴士:原先原型上的 $mount 方法在 src/platform/web/runtime/index.js 中定义,之所以这么设计完全是为了复用,因为它是可以被 runtime only 版本的 Vue 直接使用的。】

 

接下来我们再来看$mount 方法的定义

Vue.prototype.$mount = function (
  el?: string | Element,
  hydrating?: boolean
): Component {
  el = el && inBrowser ? query(el) : undefined
  return mountComponent(this, el, hydrating)
}

这里$mount 方法支持传入 2 个参数,第一个是 el,它表示挂载的元素,可以是字符串,也可以是 DOM 对象,如果是字符串在浏览器环境下会调用 query 方法转换成 DOM 对象的。第二个参数是和服务端渲染相关,在浏览器环境下我们不需要传第二个参数。接着$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
    if (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
        )
      }
    }
  }
  callHook(vm, 'beforeMount')

  let updateComponent
  /* istanbul ignore if */
  if (process.env.NODE_ENV !== 'production' && config.performance && mark) {
    updateComponent = () => {
      const name = vm._name
      const id = vm._uid
      const 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 = () => {
      vm._update(vm._render(), hydrating)
    }
  }

  // we set this to vm._watcher inside the watcher's constructor
  // since the watcher's initial patch may call $forceUpdate (e.g. inside child
  // component's mounted hook), which relies on vm._watcher being already defined
  new Watcher(vm, updateComponent, noop, {
    before () {
      if (vm._isMounted) {
        callHook(vm, 'beforeUpdate')
      }
    }
  }, true /* isRenderWatcher */)
  hydrating = false



  // manually mounted instance, call mounted on self
  // mounted is called for render-created child components in its inserted hook
  if (vm.$vnode == null) {
    vm._isMounted = true
    callHook(vm, 'mounted')
  }
  return vm
}

从上面的代码可以看到,mountComponent 核心就是先调用 vm._render 方法先生成虚拟 Node,再实例化一个渲染Watcher,在它的回调函数中会调用 updateComponent 方法,最终调用 vm._update 更新 DOM。

Watcher 在这里起到两个作用,一个是初始化的时候会执行回调函数,另一个是当 vm 实例中的监测的数据发生变化的时候执行回调函数。函数最后判断为根节点的时候设置 vm._isMounted 为 true, 表示这个实例已经挂载了,同时执行 mounted 钩子函数。 这里注意 vm.$vnode 表示 Vue 实例的父虚拟 Node,所以它为 Null 则表示当前是根 Vue 的实例。

 

写在最后:

mountComponent 方法的逻辑也是非常清晰的,它会完成整个渲染工作,渲染中最核心的 2 个方法:vm._render 和 vm._update。

Vue源码系列(一):Vue源码解读的正确姿势 作为一名开发人员,阅读源码是非常好的学习方式,尤其Vue又是当下很受欢迎的前端框架,随着用的人越来越多,不断推动着源码地完善。在源码中有着各位大佬多年积淀下来的精华,而这些精华就非常值得我们学习。 阅读详情

相关推荐

面试官:Vue实例挂载的过程

源码位置:src\platforms\web\runtime\index.js。源码位置:src\core\instance\lifecycle.js。源码位置:src\core\instance\render.js。源码位置:src\core\instance\index.js。源码位置:src\core\instance\state.js。源码位置:src\core\instance\init.js。过程中是如何完成数据的绑定,又是如何将数据渲染到视图的等等。的时候,数据已经初始化完成,能够访问。

jiadsadfasfs的博客 1245

Vue基础知识

Vue基础,数据响应式原理,数据绑定等

sjsja的博客 1930

Vue实例挂载的过程

源码位置:src\platforms\web\runtime\index.js。源码位置:src\core\instance\lifecycle.js。源码位置:src\core\instance\render.js。源码位置:src\core\instance\index.js。源码位置:src\core\instance\state.js。源码位置:src\core\instance\init.js。过程中是如何完成数据的绑定,又是如何将数据渲染到视图的等等。的时候,数据已经初始化完成,能够访问。

yousuotu的博客 1057

Vue之深入理解extend与手动挂载$mount

这样既可以使用 .vue 来写复杂的组件(毕竟在 template 里堆字符串很痛苦),还可以根据需要传入适当的 props。上一章节我们说到,创建一个vue实例的时候,都会有一个选项el,来指定实例的根节点,如果不写el选项,那组件就处于未挂载状态。方法对组件进行了手动渲染,但它仅仅是被渲染好了,并没有挂载到节点上,也就显示不了组件。的作用,就是基于 Vue 构造器,创建一个“子类”,它的参数跟。,就可以让组件渲染,并且挂载到任意指定的节点上,比如 body。手动渲染的组件,如果要销毁,也要用。

梦想成为全栈的切图仔 1408

vuejs源码之实例对象挂载分析

vm.$mount的实现逻辑 在new Vue(options)之后,vue做了一系列的初始化过程,在init()函数最后进行了挂载操作。 if (vm.$options.el) { vm.$mount(vm.$options.el) } vm.$mount方法在多个地方都有定义,如 src/platform/web/entry-runtime-with-compiler.js、src/platform/web/runtime/index.js、src/platform/weex/runtim

weixin_43213137的博客 404

【Vue3源码学习】— CH3.1 apiCreateApp.ts: 创建Vue应用实例

在Vue 3中,createApp是启动Vue应用的核心。apiCreateApp.ts文件包含了创建Vue应用实例的API,不仅允许开发者挂载根组件,还提供了配置全局属性、指令和组件的能力。本文将深入探讨createApp的工作原理和它提供的各种方法。

YSG的博客 1404

浅谈Vue.$mount()使用以及原理

一、作用 Vue 的$mount()为手动挂载,在项目中可用于延时挂载(例如在挂载之前要进行一些其他操作、判断等),之后要手动挂载上。new Vue时,el和$mount并没有本质上的不同。 具体代码如下: new Vue({ store, router }).$mount('#app') vue渲染机制流程图: 二、原理 1.$mount函数的流程: 首先,提取出el所对应的...

m0_37941483的博客 1万+

手把手教你用Payload Dumper工具,把官方卡刷包变成线刷包救砖(附Fastbootd进入方法)

本文详细介绍了如何使用Payload Dumper工具将官方卡刷包转换为线刷包进行救砖操作。通过提取payload.bin文件中的分区镜像,并利用fastbootd模式完成刷写,帮助用户解决安卓设备系统故障问题。文章包含环境搭建、工具使用、常见问题解决方案等实用内容,适合需要刷机救砖的用户参考。

weixin_42639246的博客 618

浅谈vue $mount()

Vue 的$mount()为手动挂载,在项目中可用于延时挂载(例如在挂载之前要进行一些其他操作、判断等),之后要手动挂载上。new Vue时,el和$mount并没有本质上的不同。 具体见代码: 顺便附上vue渲染机制流程图:

驚鴻入梦 7万+

HPC软件使用之ANSYS Fluent

本文介绍了如何在超级计算机上使用ANSYS Fluent进行科学计算和工程仿真。文章首先对Fluent软件进行了简要介绍,强调了其在计算流体力学领域的广泛应用和强大功能。接着,详细说明了如何编写jou脚本文件和slurm脚本文件,以控制Fluent的计算流程和作业提交。文章还提供了作业提交和查看的具体命令,并通过一个鼓风机仿真的案例演示了从网格模型准备、脚本编写、作业提交到结果查看的完整流程。最后,展示了使用Fluent进行结果可视化的方法。

欢迎各位大佬光临“寒舍”!请多多指点,共同进步! 2211

微波无源器件 功分器1 新型方波导双模无功功分器

本名证明了一种基于有着特定功能的(dedicated)T性匹配元件(散射件)的进化结点的新型波导双模两路功分器的可行性。这个散射件,有着面向三个部分的匹配部分,提供了等效功分并且朝着对应的输出端口传输矩形波导的两个TE10/TE01正交模式。所提出的设计紧凑,易于比例变化并且能够级联来获得。

qq_45245770的博客 1391

vue实例挂载的过程

vue实例挂载的过程

Sherry Tian的博客 962

1688店铺所有商品API接口(整店商品查询API接口)

1688店铺所有商品API接口、1688店铺列表API接口,1688店铺API接口,1688店铺查询商品API接口,1688店铺商品API接口,1688店铺详情接口,1688商品API接口

tbprice的博客 1568

Vue项目开发 vue实例挂载的过程?

Vue 实例的挂载过程涉及多个关键步骤,包括创建实例、编译模板、初始化数据和事件绑定等。

向着太阳迎着光 1239

Eclipse邂逅Deepseek:本地化部署全攻略

通过前面一系列的步骤,我们成功地在 Eclipse 中完成了 Deepseek 的本地化部署,并且对部署后的功能进行了测试和优化,还解决了可能遇到的一些常见问题。这一过程不仅让我们体验到了将强大的大语言模型与高效的开发环境相结合的魅力,也为我们在软件开发过程中带来了诸多便利。本地化部署 Deepseek 到 Eclipse,使得我们在代码编写过程中能够获得智能的代码补全和精准的问答支持,大大提高了开发效率。同时,本地化部署保障了数据的安全性和隐私性,避免了数据在传输过程中可能面临的风险。

远程部署调试 运行安装 项目调试 二次开发 项目技术新 持续迭代 部分源码免费分享 4519

SAP 标准 CDS View 到底能不能用 CDS Extension View 扩展,我们在项目里应该这样判断

文章摘要:判断SAP标准CDS视图(如A_PRODUCT)能否扩展字段,不能仅凭命名或@Metadata.allowExtensions判断,需检查DDL源码中的@AbapCatalog.viewEnhancementCategory值。#PROJECTION_LIST允许扩展字段,#NONE则禁止。聚合视图需额外包含#GROUP_BY,UNION视图需#UNION。CDS View Extension用于新增字段,Metadata Extension仅用于添加注解。在ABAP Cloud环境中还需检查AP

2007 年 ~ 2025 年,深耕 SAP 技术 18 年 100

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

前言在学习vue源码之前需要先了解源码目录设计(了解各个模块的功能)丶Flow语法。src├── compiler # 把模板解析成 ast 语法树,ast 语法树优化,代码生成等功能。├── core # 核心代码 Vue.js 的灵魂├── platforms # 不同平台的支持 web 和 weex├── server # 服务端渲染这部分代码是跑在服务端...

weixin_35516273的博客 757

Ceph入门到精通-存储桶通知

这 通知还可以根据前缀的匹配项过滤掉事件,并且 (1) 键的后缀,(2) 附加到对象的元数据属性, 或 (3) 对象标签。在此模式下,操作仅在以下之后确认(确认) 通知将发送到主题的已配置终端节点。这意味着 通知的往返时间(发送 通知主题的终端节点以及接收 确认)被添加到操作本身的延迟中。要更新主题,请使用用于创建主题的相同命令(但在 更新时,使用现有主题的名称和不同的终端节点值)。端口:对于未加密的连接,默认为 5672,对于未加密的连接,默认为 5671 SSL 加密连接。(默认情况下,这是“假的”。

隔壁老瓦的专栏 1131

Vue源码:vue实例挂载篇

在new一个Vue对象的时候,内部究竟发生了什么?Vue的构造类只做了一件事情,就是调用_init函数进行初始化。 2._init,初始化 _init主要做了这两件事: initData 首先判断data是不是函数,如果是函数的话执行getData。getData做的事情很简单:,因为vue推荐我们把data定义为一个函数然后返回具体的data对象,因此getData只需执行一次data拿到返回值即可。 判断是否与props属性名冲突,然后将data挂载到vue实例中。这里是通过proxy对vue实例的g

老司机的后备箱 2478

【ITS模型】基于MATLAB的ITS宽带短波信道模型的建模和仿真

1.软件版本 MATLAB2010b 2.本算法理论知识 对短波信道建模具有里程碑意义的是沃特森在1970年发表的一篇文章,文章中提出了一种静态模型,并在大气中进行了实验验证。 此静态模型可以描述为高斯散射增益抽头延迟线模型,即Watterson模型。 Watterson信道模型是经典的窄带短波信道模型,在这个模型中,信道衰落是瑞利幅度分布,而在每种传播模式中多普勒扩展的功率谱满足高斯分布。Watterson模型没有定义延时扩展的形状,认为各个多径传输模式中不存在延时扩展。其...

FPGA/MATLAB学习教程/源码/项目合作开发 2757

IEM模型,地表粗糙度模拟

利用微波反演土壤水分时候,利用IEM模型可以实现对随机地表的模拟

小白一步一步阅读vuejs源码

本篇不直接解读vuejs的双向绑定的原理,而是已读源码的视角来看vue是怎么做的。 1、下载vuejs源码 mkdir project && cd project && git clone https://github.com/vuejs/vue.git npm i 2、开始一步一步读代码 打开package.json。看看scripts,我们先只看dev,这...

3605

计算机控制技术及应用

《计算机控制技术及应用》通过总结作者的科研成果和吸收国内外的先进理论、方法和技术,以计算机控制系统的网络化、开放化、智能化和集成化发展趋势为主线索,主要介绍计算机控制系统的基本概念和计算机控制系统的典型形式,计算机控制系统的数学描述与基本分析方法,以及数字PID控制器、最少拍控制系统、达林算法、状态变量设计法等设计方法及其各种改进算法。重点突出计算机控制系统输入输出通道接口的设计方法和典型控制系统的设计案例与实现方法等。

vue3 中如何像 vue2 的 extend 一样挂载未挂载的组件,拿到标签本身($el)

vue3 中如何像 vue2 的 extend 一样挂载未挂载的组件,拿到标签本身($el) 简介:最近在用 vue3 写个新项目,需要挂载自定义的组件,但是发现 vue3 中不再支持 extend 方法了,于是查看了 vant 最新的源码,发现里面类似实现,特此提炼总结出来。 1.vue2 写法 <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8" /> <met

前端开发者 2万+

jdk-8u144-linux-x64.tar.gz.

该资源为搭建Linux系统Java环境用,资源的后缀为tar.gz格式的压缩包

TMS_WebGMaps_1.9.8.0_Full_Source

TMS_WebGMaps_1.9.8.0_Full_Source 全源码 delphi cbuilder

Vue2 中组件的本质、组件的实例化、组件实例的挂载

这篇博客的内容是讲讲在 Vue2 中,组件在底层的本质。在这里,直接抛出结论:组件的本质就是一个个的构造函数,这些函数以组件的定义 options 对象为参数,在 Vue2 中,最顶级的组件就是我们从 vue.js 中导入的 Vue 函数,而子组件是 Vue 底层通过 extend 函数创建出来的 VueComponent 函数。通过 new 这些组件的构造函数,我们可以创建出组件实例。

f18855666661的博客 2338

Vue源码解析(一),Vue中DOM的挂载过程

1.从入口开始 new Vue()做了什么 从入口文件开始,我们来分析一下new Vue()做了哪些工作,Vue实际上是一个类,我们通过new Vue() 来创建一个Vue实例。现在来看一下源码,在src/core/instance/index.js function Vue (options) { // 判断是否通过new 创建Vue实例 if (process.env.NODE_ENV...

qq_36297981的博客 3482
上一篇: Vue源码系列5------数据驱动-----从初始化到挂载
下一篇: Vue源码系列7------VueDOM渲染-----render函数
Emily Qin
博客等级 码龄10年 118粉丝 111原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值