前言

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.$mount = function (el?: string | Element,hydrating?: boolean
): Component {el = el && query(el)/* istanbul ignore if */// 报个警告,不给挂载到html和body标签上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 functionif (!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)}}} 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, {outputSourceRange: process.env.NODE_ENV !== 'production',shouldDecodeNewlines,shouldDecodeNewlinesForHref,delimiters: options.delimiters,comments: options.comments}, this)options.render = renderoptions.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重写了一遍,在重写里面添加了一些逻辑,主要就是去拿template的操作,一开始会判断一下el,看看是不是挂载到html或者body上了,是的话会报出警告,然后去拿render方法,如果没有的话就会拿el或者是template去转换为render方法,值得注意的是只有带compiler的vue版本才会去做这个render方法的转换,在runtime-only版本里面是没有的,这就是为什么使用runtime-only版本必须写render函数的原因,之后会调用一下原本的mount方法,这个mount方法定义在src/core/instance/lifecycle.js中,其实这个mount方法还是挺难找到的,只能用vscode搜索,发现重新定义mount共有三处,除了上面这处之外还有vue/src/platforms/web/runtime.js和vue/src/platforms/weex/runtime.js,重名称看应该就是vue/src/platforms/web/runtime.js,但是这个里面还是重新定义,定义里又做了一些处理,代码如下:

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

就是简单地获取一下el的dom,重要的是mountComponent,这个才是挂载的主方法,定义在src/core/instance/lifecycle.js中。

mountComponent解析

道道波折找出来的主要方法,代码如下

// 函数接受3个参数,vm,el还有最后一个是服务端渲染相关参数,这里不需要分析
export function mountComponent (vm: Component,el: ?Element,hydrating?: boolean
): Component {vm.$el = el// 如果来到这一步还没有render函数的话那说明用户使用的是runtime-only版本但是没有定义render函数,//在runtime-only版本中是没有template编译到render函数的过程的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)}}}// 调用beforeMountcallHook(vm, 'beforeMount')let updateComponent// 性能打点相关的判断,直接看else就好/* 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定义为匿名函数,函数调用_update方法去挂载dom,//这个_update方法也是Vue里面很重要的一个方法,涵盖了vnode对比和将vnode转换为dom元素渲染到页面上,//每当数据更新变化时都会被触发用来更新视图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// 这个操作很关键,这里的这个watcher是一个渲染watcher通俗地说就是掌管视图更新的,它会在初始化的时//候和数据更新的时候执行回调函数(就是传入的第二个参数updateComponent)new Watcher(vm, updateComponent, noop, {// 回调执行前执行before () {//判断是不是已经挂载过,如果挂载过的就调用beforeUpdateif (vm._isMounted && !vm._isDestroyed) {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 hookif (vm.$vnode == null) {vm._isMounted = true// 调用mountedcallHook(vm, 'mounted')}return vm
}

Vue源码解析-$mount相关推荐

  1. Vue源码解析(一)

    前言:接触vue已经有一段时间了,前面也写了几篇关于vue全家桶的内容,感兴趣的小伙伴可以去看看,刚接触的时候就想去膜拜一下源码~可每次鼓起勇气去看vue源码的时候,当看到几万行代码的时候就直接望而却 ...

  2. 前端学习(2534)vue源码解析

  3. 源码解读_入口开始解读Vue源码系列(二)——new Vue 的故事

    作者:muwoo 转发链接:https://github.com/muwoo/blogs/blob/master/src/Vue/2.md 目录 入口开始解读Vue源码系列(一)--造物创世 入口开始 ...

  4. 什么是php的ast结构,什么是AST?Vue源码中AST语法树的解析

    这篇文章给大家介绍的内容是关于什么是AST?Vue源码中AST语法树的解析,有一定的参考价值,有需要的朋友可以参考一下,希望对你有所帮助. 什么是AST AST是指抽象语法树(abstract syn ...

  5. vue源码分析系列二:$mount()和new Watcher()的执行过程

    续vue源码分析系列一:new Vue的初始化过程 在initMixin()里面调用了$mount() if (vm.$options.el) {vm.$mount(vm.$options.el);/ ...

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

    前言 在学习vue源码之前需要先了解源码目录设计(了解各个模块的功能)丶Flow语法. src ├── compiler # 把模板解析成 ast 语法树,ast 语法树优化,代码生成等功能. ├── ...

  7. 深入剖析Vue源码 - 响应式系统构建(上)

    从这一小节开始,正式进入Vue源码的核心,也是难点之一,响应式系统的构建.这一节将作为分析响应式构建过程源码的入门,主要分为两大块,第一块是针对响应式数据props,methods,data,comp ...

  8. [Vue源码分析] 模板的编译

    最近小组有个关于vue源码分析的分享会,提前准备一下- 前言: Vue有两个版本:Runtime + Compiler . Runtime only ,前者是包含编译代码的版本,后者不包含编译代码,编 ...

  9. [Vue源码分析] Virtual DOM

    最近小组有个关于vue virtual dom的分享会,提前准备一下- 读前须知: 本文章涉及源码版本为Vue 2.5.2,文中涉及到源码部分,解释直接写在源码中(中文部分为本人添加),截图尽量放完整 ...

最新文章

  1. 统计每天某一时间段的SQL语句
  2. Python中文分词 jieba 十五分钟入门与进阶
  3. leetcode 155. 最小栈(常数时间获取最小值,需要维护两个栈)
  4. grafana的+按钮_基于 Prometheus、Grafana 的 EMQ X 物联网 MQTT 服务器可视化运维监控...
  5. centos7手把手教你搭建zabbix监控
  6. Column name pattern can not be NULL or empty.
  7. python canny算法_Python 实现 Canny 边缘检测算法
  8. 服务器安装nvidia驱动_无法安装最新版NVIDIA显卡驱动,从技术角度该怎么办?
  9. Home Assistant系列 -- 设置界面语言与地理位置
  10. 计算机体系结构与计算机组成的区别
  11. linux patch 命令小结
  12. 红外传感器型号和参数_各类红外传感器比较
  13. 串口助手是怎么做出来的 :第一节,串口助手界面的实现及串口通信原理的介绍
  14. 32位cpu和64位cpu对内存地址和内存单元的差别
  15. springboot农机装备生产车间物料配送车辆调度管理系统毕业设计源码181710
  16. kettle 用cmd bat来运行ktr和kjb
  17. 学习数据数据结构的意义
  18. 2020中国卓越管理公司颁奖晚宴成功举办,四家香港科大EMBA校友企业获奖
  19. 计算机策略组 网络,组策略
  20. php大文件读取excel分割,如何用phpspreadsheet来切割excel大文件(附代码)

热门文章

  1. 如何设置qq说说展示时间_qq怎么设置时间发说?
  2. cs231n 2023春季课程理解——lecture_3
  3. IDE-goland的安装与使用
  4. Android 学习 《一》Multiple dex files define Landroid/support/design/widget/CoordinatorLayout$1;
  5. 上海和北京环境各有什么特色?
  6. linux 光驱自动弹出,Linux下弹出和收回光驱
  7. php 反射 getClass,ReflectionParameter::getClass()
  8. 90%的人跑步都白跑了!跑步的正确姿势和膝盖保养知
  9. idea中发生Can't load IA 64-bit .dll on a AMD 64-bit platform错误
  10. 用户拖欠电费,电力公司是怎样远程断电的?