热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

vue源码第一次分享

目录今天开始,我将和大家一起探索vue源码,大家一起学习!首先去git下载一份vue,我这里是v2.6.9版本的,如果要跟着一起分析的话,推荐使用同一版本!刚下载的vue的目

目录

今天开始,我将和大家一起探索vue源码,大家一起学习!
首先去git下载一份vue,我这里是v2.6.9版本的,如果要跟着一起分析的话,推荐使用同一版本!
刚下载的vue的目录结构是这样的
在这里插入图片描述



  • dist是打包生成的各种版本的vue,分为AMD,UMD,CMD,以及CommonJS四种打包格式

  • examples是一些测试用例

  • flow 是vue2用来进行静态类型检查的,这里文件是对flow语法的支持

  • types 是对ts的支持

  • packages是一些单独切出来的包,像weex

  • scripts 是关于打包的一些配置文件

  • src 就是源代码了


关于入口

很多人想看源码,但是不知道从哪一块下手,所以这里我说一下我是怎么找入口的。
首先dist文件夹中有vue.js,这是已经被打包好的js文件,src中的所有js代码都合并到了这里,我们直接去看这个vue.js肯定是会懵逼的,1w多行跳来跳去的,所以我们是不是要找到打包的入口?
那么让我们进入到scripts文件夹,因为这是打包的相关配置文件夹
在这里插入图片描述

我们这里先看build.js
看10行左右的这里 可以看到引入了config.js中所有的配置

// 把同级目录下config的所有创建配置导入
let builds = require('./config').getAllBuilds()

27行左右开始递归打包

// 开始打包
build(builds)

既然引入了配置,那我们就要进入到config.js看配置了
看38行左右

// dist目录中各种打包方式的定义
const builds = {} //里面是各种打包方式配置

我们这里可以直接ctrl+f搜索vue.js,找到dest中为vue.js的那个打包配置
这样就来到了120行左右

// 浏览器要跑的版本// Runtime+compiler development build (Browser)'web-full-dev': {// entry-runtime-with-compiler.js入口函数entry: resolve('web/entry-runtime-with-compiler.js'),// 最后输出为vue.jsdest: resolve('dist/vue.js'),format: 'umd',env: 'development',alias: { he: './entity-decoder' },banner},

可以看到输出为dist下面的vue.js,那么入口函数当然就是web/entry-runtime-with-compiler.js
显然,这个web是一个别名,我们可以通过alias.js去查找这个别名对应的目录

进入alias.js
可以在第10行看到

web: resolve('src/platforms/web'),

web别名对应着src/platforms/web
那么入口函数的路径已经出来了src/platforms/web/entry-runtime-with-compiler.js

接下来我们根据路径打开这个js文件

路径:vue-2.6.9\src\platforms\web\entry-runtime-with-compiler.js

这次分享就分析这一个js文件
将其几个代码块折叠一下,可以看到这文件其实也就3个函数:



  1. idTotemplate

  2. $mount

  3. getOuterHTML

在这里插入图片描述


$mount逐行分析

这里是不是就遇到了我们平时见到的$mount,那我们就从这个$mount开始分析

// 扩展$mount 保存老的$mount 老的$mount也会执行以前的操作
const mount = Vue.prototype.$mount
// 进行的新的mount操作
Vue.prototype.$mount = function (// 传入el,也就是挂载的元素节点el?: string | Element,// todo: 等待分析 涉及服务端渲染hydrating?: boolean
): Component {// 获取el节点el = el && query(el)// 遇到这种形式的代码,可忽略 /* istanbul ignore if */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}// 获取配置的一些选项,也就是render template el那些// 可从代码中得到一些选项的优先级:render>template>elconst options = this.$options// resolve template/el and convert to render function// 如果不存在render函数,就将template/el的设置转换为render函数// render优先级非常高了,这些操作都是在没有render的情况下进行的if (!options.render) {// 获取templatelet template = options.template// 如果有templateif (template) {// string "#app"这类的if (typeof template === 'string') {// #开头if (template.charAt(0) === '#') {// 将进入idToTemplate idToTemplate是接收#app这类,返回对应节点的innerHTMLtemplate = 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) { // 如果是DOM元素 document.querySelector()// 获取到这段内容,也就获取到了节点template = template.innerHTML} else {// 忽略if (process.env.NODE_ENV !== 'production') {warn('invalid template option:' + template, this)}return this}// 如果template不存在,获取el} else if (el) {//

// 调用getOuterHTML,获取包括标签的内容template = getOuterHTML(el)}// 这里对拿到的template进行编译if (template) {/* istanbul ignore if */if (process.env.NODE_ENV !== 'production' && config.performance && mark) {mark('compile')}// 如果是模板字符串,需要编译器去编译 也就是进入compileToFunctions这个函数// 可以通过这个函数查看编译器的工作机制,也就是把template转换为render:todoconst { render, staticRenderFns } = compileToFunctions(template, {outputSourceRange: process.env.NODE_ENV !== 'production',shouldDecodeNewlines,shouldDecodeNewlinesForHref,delimiters: options.delimiters,comments: options.comments}, this)// 赋值给当前选项的renderoptions.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')}}}// 执行老mount的操作 正常的挂载渲染过程return mount.call(this, el, hydrating)
}

很多解释已经在代码里敲好了,这里总结一下:



  1. 首先会保存老的$mount,然后进入函数,获取el和options

  2. 判断options.render是否存在,如果存在直接执行老$mount,中途那些东西都是在options.render不存在时执行的,因此可以看出render的优先级非常高了

  3. 然后当options.render不存在时,就会先判断template,再判断el,优先级由此可见:render>template>el

  4. template会检测#app,document.querySelector(’#app’),分别进行对应操作

  5. el会检测
    ,进行对应操作

  6. 当然template还会被compile解析,这里先留个todo,之后再去看compile是怎么将template转化为render函数的

这是我画的一个贼丑的图,描述了一些过程
在这里插入图片描述


idToTemplate函数

路径:当前目录

// 根据id查询到el 并返回innerHTML
const idToTemplate = cached(id => {const el = query(id)return el && el.innerHTML
})

getOuterHTML函数

路径:当前目录

// 获取包括标签的内容
function getOuterHTML (el: Element): string {// 如果存在,直接使用outerHTMLif (el.outerHTML) {return el.outerHTML} else {// 不存在就创建divconst container = document.createElement('div')// 将el深复制一份加入divcontainer.appendChild(el.cloneNode(true))// 返回这个divreturn container.innerHTML}
}

query函数

路径:vue-2.6.9\src\platforms\web\util\index.js

/* @flow */import { warn } from 'core/util/index'export * from './attrs'
export * from './class'
export * from './element'/*** Query an element selector if it's not an element already.*/
// 获取形式为“#app”的el的节点元素
export function query (el: string | Element): Element {// 如果为字符串 “#app”if (typeof el === 'string') {// 通过#app 获取到元素节点const selected = document.querySelector(el)// 如果不存在节点if (!selected) {process.env.NODE_ENV !== 'production' && warn('Cannot find element: ' + el)// 返回divreturn document.createElement('div')}// 返回获取到的节点return selected} else {// 如果不是字符串 "#app"形式,直接返回elreturn el}
}

总结

总结一下:这个入口函数,最主要的还是实现了$mount这一个函数。
下一次分享,我们将进入到vue初始化的那里去探索,当然也是通过这个入口文件去找到。怎么去找到vue初始化那里,先留个悬念在这。


推荐阅读
  • 本文记录了在vue cli 3.x中移除console的一些采坑经验,通过使用uglifyjs-webpack-plugin插件,在vue.config.js中进行相关配置,包括设置minimizer、UglifyJsPlugin和compress等参数,最终成功移除了console。同时,还包括了一些可能出现的报错情况和解决方法。 ... [详细]
  • VueCLI多页分目录打包的步骤记录
    本文介绍了使用VueCLI进行多页分目录打包的步骤,包括页面目录结构、安装依赖、获取Vue CLI需要的多页对象等内容。同时还提供了自定义不同模块页面标题的方法。 ... [详细]
  • 本文介绍了Sencha Touch的学习使用心得,主要包括搭建项目框架的过程。作者强调了使用MVC模式的重要性,并提供了一个干净的引用示例。文章还介绍了Index.html页面的作用,以及如何通过链接样式表来改变全局风格。 ... [详细]
  • Webpack5内置处理图片资源的配置方法
    本文介绍了在Webpack5中处理图片资源的配置方法。在Webpack4中,我们需要使用file-loader和url-loader来处理图片资源,但是在Webpack5中,这两个Loader的功能已经被内置到Webpack中,我们只需要简单配置即可实现图片资源的处理。本文还介绍了一些常用的配置方法,如匹配不同类型的图片文件、设置输出路径等。通过本文的学习,读者可以快速掌握Webpack5处理图片资源的方法。 ... [详细]
  • baresip android编译、运行教程1语音通话
    本文介绍了如何在安卓平台上编译和运行baresip android,包括下载相关的sdk和ndk,修改ndk路径和输出目录,以及创建一个c++的安卓工程并将目录考到cpp下。详细步骤可参考给出的链接和文档。 ... [详细]
  • imx6ull开发板驱动MT7601U无线网卡的方法和步骤详解
    本文详细介绍了在imx6ull开发板上驱动MT7601U无线网卡的方法和步骤。首先介绍了开发环境和硬件平台,然后说明了MT7601U驱动已经集成在linux内核的linux-4.x.x/drivers/net/wireless/mediatek/mt7601u文件中。接着介绍了移植mt7601u驱动的过程,包括编译内核和配置设备驱动。最后,列举了关键词和相关信息供读者参考。 ... [详细]
  • 本文总结了在开发中使用gulp时的一些技巧,包括如何使用gulp.dest自动创建目录、如何使用gulp.src复制具名路径的文件以及保留文件夹路径的方法等。同时介绍了使用base选项和通配符来保留文件夹路径的技巧,并提到了解决带文件夹的复制问题的方法,即使用gulp-flatten插件。 ... [详细]
  • 本文介绍了在使用vue和webpack进行异步组件按需加载时可能出现的报错问题,并提供了解决方法。同时还解答了关于局部注册组件和v-if指令的相关问题。 ... [详细]
  • web.py开发web 第八章 Formalchemy 服务端验证方法
    本文介绍了在web.py开发中使用Formalchemy进行服务端表单数据验证的方法。以User表单为例,详细说明了对各字段的验证要求,包括必填、长度限制、唯一性等。同时介绍了如何自定义验证方法来实现验证唯一性和两个密码是否相等的功能。该文提供了相关代码示例。 ... [详细]
  • 网络请求模块选择——axios框架的基本使用和封装
    本文介绍了选择网络请求模块axios的原因,以及axios框架的基本使用和封装方法。包括发送并发请求的演示,全局配置的设置,创建axios实例的方法,拦截器的使用,以及如何封装和请求响应劫持等内容。 ... [详细]
  • Spring常用注解(绝对经典),全靠这份Java知识点PDF大全
    本文介绍了Spring常用注解和注入bean的注解,包括@Bean、@Autowired、@Inject等,同时提供了一个Java知识点PDF大全的资源链接。其中详细介绍了ColorFactoryBean的使用,以及@Autowired和@Inject的区别和用法。此外,还提到了@Required属性的配置和使用。 ... [详细]
  • 树莓派语音控制的配置方法和步骤
    本文介绍了在树莓派上实现语音控制的配置方法和步骤。首先感谢博主Eoman的帮助,文章参考了他的内容。树莓派的配置需要通过sudo raspi-config进行,然后使用Eoman的控制方法,即安装wiringPi库并编写控制引脚的脚本。具体的安装步骤和脚本编写方法在文章中详细介绍。 ... [详细]
  • uniapp开发H5解决跨域问题的两种代理方法
    本文介绍了uniapp开发H5解决跨域问题的两种代理方法,分别是在manifest.json文件和vue.config.js文件中设置代理。通过设置代理根域名和配置路径别名,可以实现H5页面的跨域访问。同时还介绍了如何开启内网穿透,让外网的人可以访问到本地调试的H5页面。 ... [详细]
  • 本文讨论了如何使用Web.Config进行自定义配置节的配置转换。作者提到,他将msbuild设置为详细模式,但转换却忽略了带有替换转换的自定义部分的存在。 ... [详细]
  • 从零基础到精通的前台学习路线
    随着互联网的发展,前台开发工程师成为市场上非常抢手的人才。本文介绍了从零基础到精通前台开发的学习路线,包括学习HTML、CSS、JavaScript等基础知识和常用工具的使用。通过循序渐进的学习,可以掌握前台开发的基本技能,并有能力找到一份月薪8000以上的工作。 ... [详细]
author-avatar
五洋顽石_449
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有