前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >Vue组件是怎样挂载的_2023-02-27

Vue组件是怎样挂载的_2023-02-27

原创
作者头像
yyds2026
发布于 2023-02-27 05:59:15
发布于 2023-02-27 05:59:15
38802
代码可运行
举报
文章被收录于专栏:前端开发面经前端开发面经
运行总次数:2
代码可运行

我们先来关注一下$mount是实现什么功能的吧:

在这里插入图片描述
在这里插入图片描述

我们打开源码路径core/instance/init.js:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
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/props
    callHook(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内部机制吧:
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
 * 缓存之前的$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.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
            )
          }
        }
      /**       * 获取的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 = render
      options.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函数功能

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
// public mount method
Vue.prototype.$mount = function (
  el?: string | Element,  hydrating?: boolean
): Component {
  el = el && inBrowser ? query(el) : undefined
  return mountComponent(this, el, hydrating)
}

那么我们再去找一下mountComponent函数吧:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
export function mountComponent (
  vm: Component,
  el: ?Element,
  hydrating?: boolean
): Component {
  vm.$el = el
  // 如果不存在render函数,则直接创建一个空的VNode节点
  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
        )
      }
    }
  }
  // 检测完render后,开始调用beforeMount声明周期
  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 = () => {
       // 这里是上面所说的观察者,这里注意第二个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 = true
    callHook(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):

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
...

    let vnode
    try {
      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:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
render: function (createElement) {
  return createElement('h1', '标题')
}

数据我们是知道怎么更新的,那么组件tamplate到真实dom是怎么更新的呢?

在这里插入图片描述
在这里插入图片描述
  • 解析tamplate生成字符串
  • render Function处理字符串生成VNode
  • patch diff算法处理VNode

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
暂无评论
推荐阅读
Nature | 西湖大学,gsMap:空间+转录组+基因组+性状联合分析,可将空间基因表达与复杂性状相关联
◉ gsMap 首先使用图神经网络 (GNN) 学习嵌入表示,这些嵌入整合了基因表达水平、空间坐标,并可选地整合细胞类型注释先验信息。◉ 随后,gsMap 根据嵌入中的余弦相似性为每个位点识别同质位点,以形成一个微区域。◉ 每个位点依次被视为焦点位点,并通过将基因在微区域内的平均排名除以其在整个空间转录组 (ST) 切片中的平均排名,计算每个基因在每个焦点位点的特异性得分。◉ D,位点的微区域;F,基因表达特异性;G,位点空间图;R,排名;X,基因表达矩阵;Z,嵌入表示。◉ 然后,基于每个位点的 GSS(基因空间特异性得分)与其到转录起始位点 (TSS) 的距离以及 SNP 到基因的链接图,将这些 GSS 映射到单核苷酸多态性 (SNP),从而为每个位点生成一组独特的 SNP 注释。◉ 对于每个位点的 SNP GSS 注释,gsMap 使用分层连锁不平衡回归 (S-LDSC) 来评估具有更高 GSS 的 SNP 是否对目标性状的遗传力有显著富集。◉ LD,连锁不平衡。◉ 为了量化某个空间区域与性状关联的显著性,gsMap 使用柯西组合检验来聚合该空间区域内位点的 P 值。
生信菜鸟团
2025/05/23
3070
Nature | 西湖大学,gsMap:空间+转录组+基因组+性状联合分析,可将空间基因表达与复杂性状相关联
GWAS公开结果哪里找,GWAS Catalog来帮忙
GWAS Catalog是EBI旗下的一个数据库,收录了公开发表的GWAS分析结果,截止2019-11-21,收录了16万个SNP位点和疾病之间的关联信息,更多信息汇总如下
生信修炼手册
2019/12/19
4.1K1
GWAS公开结果哪里找,GWAS Catalog来帮忙
CAUSALdb:涵盖数千个GWAS研究和Fine-mapping结果的可视化数据库
现在 GWAS 研究越来越多。要查询以往的 GWAS 研究结果,可以使用 GWAS Catalog。GWAS Catalog 包含的信息非常多,不过有时可能满足不了需要。这里,推荐一个叫 CAUSALdb 的数据库。
实验盒
2021/09/22
1.3K0
CAUSALdb:涵盖数千个GWAS研究和Fine-mapping结果的可视化数据库
R包“ieugwasr“教程---SNP信息查询
在孟德尔随机化研究中,我们常常会碰到SNP没有rsid的情况,这个时候需要我们把rsid添加上,如果SNP的个数不是很多的话,我们可以使用variants_chrpos()函数:
生信与临床
2022/08/21
5.7K0
R包“ieugwasr“教程---SNP信息查询
COSMIC数据库详细梳理
Drug development proceeds via a series of widely-recognised phases.Actionability uses an extended version of the FDA’s phase definitions. Possible values are: Approved FDA, Approved other, Phase 3, Phase 2, Phase 1, Experimental, Orphan/Fast track, Case study, Out of trials human study, Retrospective/Meta-analysis, Phase 4, Unknown.
追风少年i
2024/06/07
3040
COSMIC数据库详细梳理
如何获取完整的GWAS summary数据(1)------GWAS catalog数据库
在孟德尔随机化(Mendelian randomization,MR)研究中,对于暴露数据我们只需要那些显著的SNP信息,这样的信息在各种GWAS数据库中都是很容易获取的。但是,关于结局的数据,由于需要SNP和结局不相关,所以很多时候这种不显著的结果无法直接从文章或者数据库中查询到,这时候我们需要下载完整的GWAS summary数据了,这种数据一般包含上百万乃至上千万的SNP信息,所以数据量比较大(压缩后在200M左右),希望大家有所认识,有所准备。
生信与临床
2022/08/21
9K0
如何获取完整的GWAS summary数据(1)------GWAS catalog数据库
mqtldb-meQTL预测数据库
之前我们在[[SNP是什么东西?#QTL]]当中提到过,QTL是一种用来预测SNP功能的算法。一般分析SNP影响哪个方面的功能就在前面加什么前缀。[[表观遗传学简介]]当中的DNA甲基化 (DNA methylation) 是一种通过给DNA序列添加甲基来影响基因功能的方式。如果要分析SNP对甲基化的影响,那么就会有meQTL (methylation QTL) 这样的东西。所以这里就给大家介绍两个关于meQTL预测的数据库。Pancan-meQTL: http://gong_lab.hzau.edu.cn/Pancan-meQTL/
医学数据库百科
2022/09/02
8070
mqtldb-meQTL预测数据库
数据库介绍 | PharmGWAS:一个基于GWAS的药物再利用知识库
生信菜鸟团
2024/11/23
2390
数据库介绍 | PharmGWAS:一个基于GWAS的药物再利用知识库
R包“ieugwasr“教程---功能介绍与分析
在进行孟德尔随机化(Mendelian randomization, MR)研究时,我们最常使用的一个R包就是“TwoSampleMR”,这个包是由“MRCIEU”团队开发的。除此之外,该团队还开发了“PHESANT”这个使用非常广泛的R包以及“open GWAS”这个数据库。
生信与临床
2022/08/21
3.7K0
R包“ieugwasr“教程---功能介绍与分析
玩转 ENSEMBL 数据库 (一)
生物信息学离不开数据库的使用,一般情况下,我们似乎能难使用一个数据库的全部功能,但不可否认的是,一个数据库往往隐藏着我们不知道的使用技巧,也可能我们使用过这些功能,但不够完整。所以这里我们一起探索一下数据库的使用奥秘及深度解读信息。
生信菜鸟团
2025/04/22
3320
玩转 ENSEMBL 数据库 (一)
lncRNAs和circRNAs数据更新及分析工具:Lnc2cancer 3.0
Lnc2Cancer 3.0由哈尔滨医科大学李霞老师和宁尚伟老师课题组开发,发表在2020年10月13日发表在Nucleic Acids Research杂志上。
作图丫
2022/03/29
8630
lncRNAs和circRNAs数据更新及分析工具:Lnc2cancer 3.0
孟德尔分析:代谢疾病相关的GWAS数据库
继上周分享了血液中的蛋白组学相关网站后➡【孟德尔随机化】血液循环中的蛋白质组:常用网站一网打尽,今天我们继续扩充孟德尔随机化GWAS数据的来源吧~
生信菜鸟团
2023/09/09
2.8K0
孟德尔分析:代谢疾病相关的GWAS数据库
Hail-GWAS教程笔记
主要参考自:Hail | GWAS Tutorial[1]本笔记旨在提供Hail功能的概述,重点是操作和查询遗传数据集的功能。我们进行了全基因组SNP关联测试,并证明了需要控制由群体分层引起的混杂。
用户1075469
2022/03/04
1.2K0
Hail-GWAS教程笔记
NatMed | 有源代码 | 多基因风险评分识别出不同类型的脂肪肝疾病
Fig. 4: mRNA expression of loci from the liver-specific (discordant) polygenic risk score is more abundant in the liver compared to the visceral adipose tissue.
生信菜鸟团
2025/01/10
1640
NatMed | 有源代码 | 多基因风险评分识别出不同类型的脂肪肝疾病
DNA语言基础模型,从DNA序列中准确预测分子表型 | Nat.Methods
- 图片说明- a,b,NT训练概述(a)及其通过微调在下游基因组预测任务中的应用(b)。通过探测进行的下游任务预测类似,但没有NT中的重新缩放权重。c,NT模型与其他基础基因组学模型在感知场大小、参数数量和我们基准中包含的18个精选下游任务性能方面的比较。d,为下游任务考虑的基因组特征的图形表示(改编自其他地方48)。- ,
生信菜鸟团
2025/02/20
2130
DNA语言基础模型,从DNA序列中准确预测分子表型 | Nat.Methods
这些功能很哇塞的植物科学数据库,你用过几个?
科学数据库不仅可以全面展示相关科研成果,同时还可以作为重要的数据及分析资源,最大化科研成果的转化率,提升同领域科研工作者的科研效率。12月盘点季,小编就给大家推荐几个超级实用的植物科学数据库...
尐尐呅
2022/04/01
8910
这些功能很哇塞的植物科学数据库,你用过几个?
GWAS综述(生信文献阅读俱乐部精选)
从具有遗传标记的复杂性状的统计学关联推进到理解影响性状的功能性遗传变异往往是一个复杂的过程。精细定位可以选择遗传变异并对其进行优先级排序以供进一步研究,但是大量的分析策略和研究设计使得选择最佳方法具有挑战性。作者回顾了不同精细绘图方法的优缺点,强调了影响性能的主要因素。主题包括全基因组关联研究(GWAS)的解释结果,连锁不平衡的作用,统计精细绘图方法,跨种族研究,基因组注释和数据整合以及其他分析和设计问题。
生信技能树
2018/11/30
5.2K0
GWAS综述(生信文献阅读俱乐部精选)
Hail-GWAS教程笔记
主要参考自:Hail | GWAS Tutorial[1]本笔记旨在提供Hail功能的概述,重点是操作和查询遗传数据集的功能。我们进行了全基因组SNP关联测试,并证明了需要控制由群体分层引起的混杂。
生信技能树
2023/02/27
6940
Hail-GWAS教程笔记
生信程序 | Nat.Genet | 在疾病关联位点精细定位因果组织和基因
生信菜鸟团
2025/02/06
1890
生信程序 | Nat.Genet | 在疾病关联位点精细定位因果组织和基因
统计遗传学:第九章,GWAS+群体分析+亲缘关系分析
本篇,使用数据和代码演示的形式,展示了GWAS分析、群体结构分析、亲缘关系分析三部分内容。我又重演了一遍,修正了一些bug。文中代码和数据我回头专门整理相关博文进行分享。
邓飞
2022/12/12
4.1K0
统计遗传学:第九章,GWAS+群体分析+亲缘关系分析
推荐阅读
相关推荐
Nature | 西湖大学,gsMap:空间+转录组+基因组+性状联合分析,可将空间基因表达与复杂性状相关联
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档