1. 认识 Vue.js
1.1 为什么要学习 Vue
如果从现实(找工作)的角度出发,学好 Vue
你可以找到一份满意的前端工作,而没有掌握 Vue
则很难找到一份满意的前端工作(需要补充的是,除了 Vue
,现在不少岗位对“小程序”也有要求)。
1.2 Vue
的特点
Vue
(读音 /vjuː/
,类似于 view
)是一套用于构建用户界面的渐进式 JavaScript
框架:
- 全称是
Vue.js
或Vuejs
; - 什么是渐进式框架呢?
- 渐进式框架意味着我们可以在项目中一点点地引入和使用
Vue
,而不一定需要全部使用Vue
来开发整个项目。你可以选择使用(或不使用)Vue
的某部分功能,你也可以只在项目的某个模块中使用Vue
。
- 渐进式框架意味着我们可以在项目中一点点地引入和使用
1.3 Vue
和 React
等框架的对比
目前前端最流行的三大框架:Vue
、React
、Angular
。
Angular
:入门门槛较高,并且国内市场占有率较低。但不否认其本身是非常优秀的框架,它的很多设计思想与Node
框架nest.js
相似,而且它们基本上都要用TypeScript
开发。React
:国内外的市场占有率都较高。作为前端工程师也是必须学习的一个框架。大公司大项目在以前也更倾向于使用React
开发,因为相对来说React
可能更加的灵活,一些Vue2
可能没法做的场景React
则可以做(当然,现在Vue
从2
版本升级到3
版本后,有了Composition API
,也非常灵活了)。Vue
:在国内市场占有率最高,几乎所有的前端岗位都会对Vue
有要求。
1.3.1 框架数据对比
1.3.1.1 Google
指数
1.3.1.2 百度指数
1.3.1.3 npm
下载量
1.3.1.4 GitHub
1.3.2 谁是最好的前端框架
这里不给出结论,因为就像人们争论谁是世界上最好的语言一样,争论这个问题没有意义。
但我们不妨从现实的角度先分析一下,学习哪门语言更容易找工作(哪门语言市场占有率更高)?
- 找后端的工作:优先推荐
Java
,其次是Go
,再次是Node
(JavaScript
),可能不推荐PHP
、C#
; - 找前端的工作:优先推荐
JavaScript
(TypeScript
),其次是Flutter
,再次是Android
(Java
、Kotlin
)、iOS
(OC
、Swift
); - 其它方向:算法工程师、游戏开发、人工智能等等。
那么,就前端来说,学习了 HTML
、CSS
、JavaScript
之后,哪一个框架更容易找到工作?
- 如果去国外找工作,优先推荐
React
,其次是Vue
和Angular
,不推荐jQuery
了; - 如果在国内找工作,优先推荐、必须学习
Vue
,其次是React
,再次是Angular
,不推荐jQuery
了。
1.4 学习 Vue2
还是 Vue3
- 对于已经掌握
Vue2
的同学来说,直接学习Vue3
中相关的内容即可; - 对于没有学过
Vue2
的同学,直接学习Vue3
就行了。
《程序员》:Vue 3
版本兼容 2.x
,对于想要学习 Vue
的开发者而言,时常在纠结是从 Vue2
开始学基础还是直接学 Vue3
,对此,你有着什么样的建议?
尤雨溪(Vue
作者):直接学 Vue 3
就行了,基础概念是一模一样的。
1.5 目前需要学习 Vue3
吗
2020
年 9
月 18
日,万众期待的 Vue3
终于发布了正式版,命名为 “One Piece
”。
- 它带来了很多新的特性:更小的体积、更好的性能、更优秀的
API
设计、更好的TypeScript
集成; - 在
Vue3
刚刚发布时,很多人跃跃欲试,想要尝试Vue3
的各种新特性,这时我们用Vue3
写写demo
练习是没有问题的,但真正在实际业务项目中使用Vue3
还需要一个相对过程; - 包括
Vue3
的进一步稳定、社区更多Vue3
相关的插件、组件库的支持和完善(因为生态需要时间,生态里的工具、周边以及库都需要时间去兼容,Vue3
的一些新用法也需要时间去沉淀)。
那么现在是否是学习 Vue3
的时间呢?
- 答案是肯定的;
- 首先
Vue3
在经过一系列的更新和维护后,已经趋于稳定,并且尤雨溪之前在VueConf China 2021
上也宣布会在今年(2021)第二季度将Vue3
作为默认版本(现在的时间是7
月10
号,npm
还没有默认安装Vue3
,文档也还没有默认指向v3
文档)。 - 社区经过一段时间的沉淀后,也更加完善了,包括
Ant Design Vue
、Element Plus
都提供了对Vue3
的支持,所以很多公司目前新的项目都已经在使用Vue3
来进行开发了。 - 并且在面试中,也会问到
Vue3
、Vite2
工具相关的问题。
1.6 Vue3
带来的变化
1.6.1 源码
- 源码通过
monorepo
的形式来管理mono
:单个;repo
:repository
(仓库);- 就是将许多项目的代码存储在同一个仓库中;
- 这样做可以使得多个包本身相互独立,可以有自己的功能逻辑、单元测试等,同时又在同一个仓库下,方便管理;
- 而且模块划分得更加清晰,可维护性、可扩展性更强。
- 源码使用
TypeScript
进行了重写- 在
Vue2.x
时,Vue
使用Flow
进行类型检测; - 现在到了
Vue3.x
,Vue
的源码全部使用TypeScript
进行重构,并且Vue
本身对TypeScript
的支持也更好了。
- 在
1.6.2 性能
- 使用
Proxy
进行数据劫持- 在
Vue2.x
的时候,Vue2
是使用Object.defineProperty
来劫持数据的getter
和setter
方法的; - 这种方式一直存在一个缺陷:当给对象添加或删除属性时,无法劫持和监听;
- 所以在
Vue2.x
的时候,不得不提供一些特殊的API
,比如$set
、$delete
,事实上都是一些hack
方法,增加了开发者学习新的API
的成本; - 而在
Vue3.x
开始,Vue
使用Proxy
来实现数据的劫持,该API
的用法和相关原理后续会讲到;
- 在
- 删除了一些不必要的
API
- 移除了实例上的
$on
、$off
和$once
; - 移除了一些特性:
filters
(过滤器)、inline template attribute
(内联模板属性)等;
- 移除了实例上的
- 编译方面的优化
- 生成
Block Tree
; Slot
编译优化;diff
算法优化;
- 生成
1.6.3 新的 API
- 由
Options API
到Composition API
- 在
Vue2.x
的时候,我们会通过Options API
来描述组件对象; Options API
包括props
、data
、computed
、watch
、生命周期事件、methods
等等选项;Options API
存在比较大的问题是多个逻辑可能是在不同的地方:- 比如
created
中会使用methods
中的某个方法来修改data
中的数据,代码的内聚性非常差;
- 比如
- 而
Composition API
可以将相关联的代码放到同一处进行处理,而不需要分散在多个Options
中,也就不用再在多个Options
之间寻找了;
- 在
Hooks
函数增加代码的复用性- 在
Vue2.x
的时候,我们通常通过mixins
在多个组件之间共享逻辑; - 但是有一个很大的缺陷就是
mixins
也是由一大堆的Options
组成的,多个mixins
间会存在命名冲突的问题; - 到了
Vue3.x
,我们可以通过Hook
函数将一部分独立的逻辑抽取出去,并且它们还可以做到是响应式的; - 具体的好处,会在后续演练和讲解(包括原理);
- 在
2. Vue
的安装
简单认识了 Vue
之后,如何使用它呢?
首先,我们要知道,Vue
的本质就是一个 JavaScript
库。刚开始我们不需要把它想象的非常复杂,只需把它理解成一个已经帮助我们封装好的库,在项目中我们可以引入并使用它。
使用 Vue
之前,我们需要先安装 Vue
,安装 Vue
这个 JavaScript
库的方式有以下 4
种:
- 在页面中通过
CDN
的方式引入; - 下载
Vue
的JavaScript
文件后在页面中手动引入; - 通过
npm
包管理工具安装(讲Webapck
时再讲); - 直接安装
Vue CLI
,安装Vue CLI
时会安装Vue
(讲完Webpack
后讲脚手架时再讲,后续我们通过Vue CLI
创建项目并使用Vue
);
2.1 方式一、CDN
引入
- 什么是
CDN
呢?CDN
即内容分发网络(Content Delivery Network
或Content Distribution Network
,缩写:CDN
)- 它是指通过相互连接的网络系统,利用最靠近每位用户的服务器;
- 更快、更可靠地将音乐、图片、视频、应用程序及其它文件发送给用户;
- 来提供高性能、可扩展性及低成本的网络内容传递给用户。
- 常用的
CDN
服务器可以分为两种:- 自己的
CDN
服务器:需要购买自己的CDN
服务器,目前华为、阿里、腾讯、亚马逊、谷歌等平台上都可以购买CDN
服务器; - 开源的
CDN
服务器:国际上使用比较多的是unpkg
、JSDelivr
、cdnjs
;
- 自己的
- 通过
CDN
引入Vue
的最新版本:
<script src="https://unpkg.com/vue@next"></script>
在浏览器中访问 https://unpkg.com/vue@next
这一 CDN
地址也可以看到 Vue
打包后没有经过压缩的源代码(在开发阶段建议用没有经过压缩的代码,这样可以看到更多细节):
可以看到,该文件的最上面定义了一个全局变量 Vue
(其实是一个对象),因此,我们接下来就是通过这个全局变量 Vue
来使用 Vue
了。
Hello Vue
案例的实现:
<!-- 4. 用来给 app 对象挂载的元素(通常为 div,并且设置 id 为 app,但也可以使用其它元素和其它
选择器) -->
<div id="app"></div>
<!-- 1. CDN 引入 Vue -->
<script src="https://unpkg.com/vue@next"></script>
<script>
const obj = {
// 3. 在 template 属性中声明后续 createApp 函数返回的 app 对象中要显示的内容
template: '<h2>Hello Vue</h2>'
};
// 2. 调用全局变量 Vue 中的 createApp 函数,
// 该函数要求传入一个对象,而其返回值也是一个对象
const app = Vue.createApp(obj);
// 5. 将 app 对象挂载到 id 为 app 的 HTML 元素上(即告诉 app 对象要在哪里显示)
// 这里我们不需要通过 document.querySelector 方法手动去拿目标元素,只需要传入要匹配的选择器的
// DOM 字符串即可,因为 Vue 内部会根据这里传入的字符串帮助我们用 document.querySelector 去找到
// 目标元素(源码中对应的代码:packages/runtime-dom/src/index.ts -> createApp -> app.mount ->
// normalizeContainer(containerOrSelector) -> if (isString(container)) ->
// document.querySelector(container))
app.mount('#app');
</script>
总结一下上述案例使用 Vue
的 5
个步骤:
- 引入
Vue
; - 创建一个包含模板的对象;
- 通过全局变量
Vue
调用createApp
方法(对象中的函数称之为方法)并传入该对象; - 返回的对象调用
mount
方法把自己挂载到某个元素上; - 页面上显示出模板内容;
2.2 方式二、下载后引入
下载 Vue
的源码,可以直接打开 CDN
的链接:
- 打开链接(unpkg.com/vue@next ),复制其中所有的代码;
- 创建一个新的文件,如
vue.js
,将复制的代码粘贴进该文件中。
接下来,就可以(比如在“本地引入.html
”中)通过 script
标签引入刚才创建的新文件:
<script src="./js/vue.js"></script>
你好啊,Vue3
案例的实现:
<div id="app"></div>
<script src="./js/vue.js"></script>
<script>
Vue.createApp({
template: '<h2>你好啊,Vue3</h2>'
}).mount('#app');
</script>
3. 计数器案例
下面我们来实现一个计数器的案例:
- 点击
+1
按钮,页面内容会显示数字+1
; - 点击
-1
按钮,页面内容会显示数字-1
;
可以选择很多种方式来实现,我们这里选择用原生的方式和 Vue
的方式分别实现,并比较两者的不同。
3.1 原生实现
<h2 class="counter"></h2>
<button class="increment">+1</button>
<button class="decrement">-1</button>
<script>
// 1. 获取展示当前计数的元素和两个按钮元素
const counterEl = document.querySelector('.counter');
const incrementBtnEl = document.querySelector('.increment');
const decrementBtnEl = document.querySelector('.decrement');
// 2. 定义一个变量,用来记录当前计数
let counter = 0;
// 3. 为展示当前计数的元素内容赋初值
counterEl.innerHTML = counter;
// 4. 为按钮添加点击事件的监听
incrementBtnEl.addEventListener('click', () => {
counter++;
counterEl.innerHTML = counter;
});
decrementBtnEl.addEventListener('click', () => {
counter--;
counterEl.innerHTML = counter;
});
</script>
3.2 Vue
实现
<div id="app"></div>
<!-- 引入 Vue -->
<script src="./js/vue.js"></script>
<script>
Vue.createApp({
// 模板内容有点多,写在一行不好写,可以采用 ES6 新增的模板字面量定义字符串,这样就能保留换行字符,
// 可以跨行定义字符串了。
// 下面模板内容的最外层包了个 div,这是 Vue2 的要求,而到了 Vue3 中,可以去掉这个 div。
// Vue3 的 template 最外层根元素(如下面的 div)可以不加(Vue2 必须要加一层根元素进行包裹,
// 否则会报错:Component template should contain exactly one root element. If you are
// using v-if on multiple elements, use v-else-if to chain them instead.)。
// 模板中可以通过“Mustache”语法(双大括号)使用下面 data 函数属性返回对象中的属性;
// 模板中可以通过“@click”绑定点击事件,与下面 methods 对象中的属性进行绑定。
template: `
<div>
<h2>{{ message }}</h2>
<h2>{{ counter }}</h2>
<button @click="increment">+1</button>
<button @click="decrement">-1</button>
</div>
`,
// createApp 函数需要传入的是一个对象,对象是可以有多个属性的,
// 而 Vue 中规定了,这里还可以有 data 属性。
// Vue3 中 data 属性对应的值需要是一个函数并返回一个对象,而不允许直接传对象,
// 否则会报错:Uncaught TypeError: dataFn.call is not a function(Vue2 中 data 可以直接传一个对象)
data() {
return {
// data 函数返回的对象中可以定义任意属性;
// 它们都会被加入到 Vue 的响应式系统中,所以都是响应式的;
// 它们都可以在模板中使用
message: 'Hello World',
counter: 0
};
},
// 还可以有 methods 属性
// methods 属性对应一个对象,里面可以定义各种各样的方法
methods: {
// 定义“加一”操作的方法(ES6 之前对象中定义方法的语法)
increment: function() {
console.log('点击了 +1');
// methods 中可以通过 this 拿到 data 中的数据(本质上拿到的是 Proxy)
this.counter++;
},
// 定义“减一”操作的方法(ES6 对象中定义方法的语法糖,即简写形式)
decrement() {
console.log('点击了 -1');
this.counter--;
}
}
}).mount('#app');
</script>
我们还可以对上述代码做一点抽取(template
的抽取 4.1.1
节会详细讲),修改如下:
<div id="app"></div>
<template id="my-app">
<h2>{{ message }}</h2>
<h2>{{ counter }}</h2>
<button @click="increment">+1</button>
<button @click="decrement">-1</button>
</template>
<script src="./js/vue.js"></script>
<script>
const App = {
template: '#my-app',
data() {
return {
message: 'Hello World',
counter: 0
};
},
methods: {
increment: function() {
console.log('点击了 +1');
this.counter++;
},
decrement() {
console.log('点击了 -1');
this.counter--;
}
}
};
Vue.createApp(App).mount('#app');
</script>
3.3 命令式和声明式
我们会发现,原生开发和 Vue
开发的模式和特点是完全不同的,这里其实涉及到两种不同的编程范式:
- 命令式编程和声明式编程;
- 命令式编程关注的是 “怎么做”(
how to do
);声明式编程关注的是 “做什么”(what to do
),”怎么做“(how to do
)的过程交给框架(机器)完成。
在原生的实现过程中,我们是如何操作的呢?
- 我们每完成一个操作,都需要通过
JavaScript
编写一条代码,来给浏览器一个指令; - 这样的编写代码的过程,我们称之为命令式编程;
- 在早期的原生
JavaScript
和jQuery
开发中,我们都是通过这种命令式的方式编写代码的;
在 Vue
的实现过程中,我们是如何操作的呢?
- 我们会在
createApp
传入的对象中声明需要的内容:模板(template
)、数据(data
)、方法(methods
),剩下的具体操作则由Vue
帮助我们完成; - 这样编写代码的过程,我们称之为声明式编程;
- 目前
Vue
、React
、Angular
的编程模式,都是这种声明式。
3.4 MVVM
模型
-
MVC
和MVVM
都是一种软件的体系结构:MVC
是Model-View-Controller
的简称,是前期使用非常广泛的框架的架构模式,比如iOS
、前端;MVVM
是Model-View-ViewModel
的简称,是目前非常流行的架构模式;
-
通常情况下,我们也称
Vue
是一个MVVM
的框架Vue
官网其实有说明:“虽然没有完全遵循MVVM
模型,但是Vue
的设计也受到了它的启发”。
前面原生实现计数器的代码就可以按照 MVC
的软件体系结构进行划分(虽然划分得不是很清晰):
而前面 Vue
实现计数器的代码则是按照 MVVM
的软件架构模式编写的:
综上,计数器的原生实现可以看成是一个 MVC
架构模式的命令式编程,计数器的 Vue
实现可以看成是一个 MVVM
架构模式的声明式编程。
4. template
、data
、methods
属性详解
在使用 createApp
的时候,我们传入了一个对象,下面我们详细解析一下之前传入的属性分别代表什么含义。
4.1 template
属性
template
属性表示的是 Vue
需要帮助我们渲染的模板信息。
- 目前我们看到它里面有很多的
HTML
标签,这些标签会替换掉我们挂载到的元素(我们这里是id
为app
的div
)的innerHTML
;- 源码中对应的代码:
packages/runtime-dom/src/index.ts
->createApp
->app.mount
->container.innerHTML = ''
,Vue
会在挂载前清空里面的内容;
- 源码中对应的代码:
- 模板中有一些奇怪的语法,比如
{{}}
、@click
,这些都是模板特有的语法,我们会在后面讲到;
但是这个模板的写法有点别扭,并且 IDE
很有可能没有任何提示,有碍我们编程的效率。
4.1.1 template
写法
好消息是,Vue
为我们提供了另外两种方式来编写 template
:
- 方式一:使用
script
标签,同时标记它的类型为x-template
,设置id
;
<script type="x-template" id="my-app">
<div>
<h2>{{ message }}</h2>
<h2>{{ counter }}</h2>
<button @click="increment">+1</button>
<button @click="decrement">-1</button>
</div>
</script>
- 方式二:使用任意标签(通常是
template
标签,因为它不会被浏览器渲染),设置id
;HTML
内容模板(<template>
)元素是一种用于保存HTML
的机制,它不会在页面加载完后立即被渲染(呈现),但随后在运行时使用JavaScript
期间可能会被实例化。1
<template id="my-app">
<div>
<h2>{{ message }}</h2>
<h2>{{ counter }}</h2>
<button @click="increment">+1</button>
<button @click="decrement">-1</button>
</div>
</template>
- 这个时候,在给
createApp
函数传入的对象中,我们需要传入的template
以#
开头- 如果字符串是以
#
开始,那么它将被用作querySelector
,并且使用匹配元素的innerHTML
作为模板字符串。
- 如果字符串是以
方式一完整代码:
<div id="app"></div>
<script type="x-template" id="my-app">
<div>
<h2>{{ message }}</h2>
<h2>{{ counter }}</h2>
<button @click="increment">+1</button>
<button @click="decrement">-1</button>
</div>
</script>
<script src="./js/vue.js"></script>
<script>
Vue.createApp({
template: '#my-app',
data() {
return {
message: 'Hello World',
counter: 0
};
},
methods: {
increment: function () {
this.counter++;
},
decrement() {
this.counter--;
}
}
}).mount('#app');
</script>
方式二完整代码:
<div id="app"></div>
<template id="my-app">
<div>
<h2>{{ message }}</h2>
<h2>{{ counter }}</h2>
<button @click="increment">+1</button>
<button @click="decrement">-1</button>
</div>
</template>
<script src="./js/vue.js"></script>
<script>
Vue.createApp({
template: '#my-app',
data() {
return {
message: 'Hello World',
counter: 0
};
},
methods: {
increment: function () {
this.counter++;
},
decrement() {
this.counter--;
}
}
}).mount('#app');
</script>
开发中,推荐使用 <template>
的方式编写模板,因为有代码提示和代码高亮。
4.2 data
属性
data
属性需要传入一个函数,并且该函数需要返回一个对象:- 在
Vue2.x
的时候,也可以传入一个对象(仅就Vue
实例而言,如果是组件的data
,则只接受function
); - 在
Vue3.x
的时候,必须传入一个函数,否则会直接在浏览器中报错;
- 在
data
中返回的对象会被Vue
的响应式系统劫持,之后对该对象的访问或修改都会在劫持中被处理;- 所以我们在
template
中通过{{ counter }}
访问counter
,可以从对象中获取到数据; - 所以我们修改
counter
的值时,template
中的{{ counter }}
也会发生改变;
- 所以我们在
- 这种响应式的具体原理,我们后面会有专门的篇幅来讲解。
4.3 methods
属性
-
methods
属性是一个对象,我们通常会在这个对象中定义很多的方法:- 这些方法可以被绑定到
template
模板中; - 在这些方法中,我们可以使用
this
关键字来直接访问到data
中返回的对象的属性;
- 这些方法可以被绑定到
-
对于有经验的同志,这里可以就官方文档中的以下这段描述2思考两个问题:
- 为什么不能使用箭头函数?(官方文档给出的解释真的理解了吗?)
- 不使用箭头函数的情况下,
this
到底指向什么?(可以作为一道面试题)
4.3.1 methods
中的方法绑定的 this
4.3.1.1 为什么不能使用箭头函数
-
我们在
methods
中要使用data
返回对象中的的数据:- 那么这个
this
就必须有值,并且应该可以通过它(this
)获取到data
返回对象中的数据。
- 那么这个
-
如果我们使用箭头函数,这里的
this
会是什么呢?this
会是window
对象
-
为什么是
window
呢?- 这就涉及到箭头函数是如何决定
this
的了:箭头函数是根据外层(函数或者全局)作用域来决定this
的,它会继承外层函数调用的this
绑定。 - 按照这个机制,这里最终找到的就是最外层
script
作用域中的this
,所以就是window
了。
- 这就涉及到箭头函数是如何决定
-
this
的到底是如何查找和绑定的呢?- 推荐阅读一篇公众号文章:前端面试之彻底搞懂this指向,里面详细讲解了
this
的绑定规则。
- 推荐阅读一篇公众号文章:前端面试之彻底搞懂this指向,里面详细讲解了
4.3.1.2 此处 this
的指向
-
this
指向组件实例对象上的proxy
对象(关于proxy
,等到后面讲响应式原理时再说); -
有关源码如下:
4.4 其它属性
当然,createApp()
函数传入的对象中还有很多其它的属性,我们会在后续进行讲解:
- 比如
props
、emits
、setup
、computed
、watch
等等; - 也包括很多的生命周期函数;
不用着急,我们会一个个学习它们的。
5. Vue
源码的下载、调试、阅读
- 有同志可能会疑惑,前面第
2
节不是已经下载了Vue
的源码了吗?怎么又要下载?- 因为前面下载的
Vue
源码是已经打包过的,所有代码都放到一个文件中了,看起来非常不方便。
- 因为前面下载的
- 也有同志可能会问,第
2
节中通过CDN
下载的Vue
的源码中不仅有ES5
的代码,怎么还有ES6
的代码呢?- 这是因为事实上最终在项目打包时,通过
babel
工具进行设置之后,这个代码还会进行一次打包(二次打包,而且还会做压缩等其它处理),所以暂时还存在ES6
的代码不会有问题。
- 这是因为事实上最终在项目打包时,通过
对于第 2
节中通过 CDN
下载的 Vue
的源码,我们可能会阅读里面的某个函数,但不会按照这份打包后的源码一点点地去读。那我们该怎么办呢?我们会这样做:
-
打开
GitHub
网站,左上方搜索框里输入vue-next
(即Vue3
版本)进行搜索; -
点击搜索结果中的
vuejs/vue-next
(我们可以看到,它是用TypeScript
写的); -
进入
vuejs/vue-next
仓库后,接下来有两种方式进行下载:
git clone
方式(推荐):点击Code
按钮,直接点击下面URL
链接后面的复制按钮复制URL
,然后我们以git clone
的方式下载源码(为什么选择这种方式?因为git
在运行它的dev
时,会依赖git
的一些东西,有用git
做一些校验。如果直接选择Download ZIP
,里面没有git
(缺少一个.git
文件夹),到时候代码可能会运行不起来):- 打开终端(
Windows
上是cmd
或者使用Git Bash
); - 通过
cd
命令进入待会下载的源码你想要存储的目录; - 执行
git clone 刚才复制的URL
命令,下载源码;
- 打开终端(
Download ZIP
方式:点击master
下拉按钮,点击Tags
标签,选择最新的稳定的版本进行下载(我们一般不会下载Branches
下的master
主分支或其它dev
分支(最终会合并到master
主分支中),因为它们很可能是正在进行开发中的代码,存在不稳定性;而Tags
下的xxx-beta.x
则是测试版,也不够稳定),我们这里就选择v3.1.4
版本进行下载:
如果你选择了 Download ZIP
的方式下载了源码,又想让源码运行起来,可以这么做:
- 先解压下载下来的源码压缩包,用
Visual Studio Code
打开解压后的文件夹(vue-next-3.1.4
); - 在
Visual Studio Code
中打开终端,输入yarn install
命令并执行;- 这里需要你电脑上之前已经安装过
node
了,并且用node
安装过yarn
了,如果没有,需要先下载node
(建议去node
官网下载“长期支持版”(LTS
)的,因为相对于“当前发布版”(Current
)的,“长期支持版”的会更稳定一点); - 下载安装完
node
之后,就会有npm
这个工具了,就可以在命令行终端执行npm install yarn -g
命令,然后你的电脑上就有yarn
这个工具了; - 因为
Vue
的源码是用yarn
来管理的(源码目录下可以看到yarn.lock
文件),所以我们需要执行yarn install
命令安装Vue
源码所需的依赖。
- 这里需要你电脑上之前已经安装过
- 执行
git init
命令将当前文件夹(vue-next-3.1.4
)初始化为一个空的Git
仓库; - 执行
git add .
命令将当前目录下的所有文件添加到暂存区; - 执行
git commit -m "fix(install): install dependences"
命令将暂存区内容提交到本地仓库中; - 执行
yarn dev
(本质上会去执行当前文件夹下package.json
文件中的scripts
中的dev
脚本对应的命令)命令,它会把当前文件夹下的packages
文件夹下的所有文件(都是Vue
的源代码)进行打包,打包后的代码会放到packages/vue/dist/vue.global.js
文件(该文件其实就是上传到CDN
上面的那个文件)中; - 有了这份打包后的源代码文件,我们就可以来到
packages/vue/examples
目录下,新建一个目录(如coderzhj
),再在该目录中新建一个html
文件(如demo.html
),接着在该文件中引入这个打包后的源码文件后,就可以用Vue
编写一些代码并在Vue
的项目里跑起来了:
而如果是通过 git clone
方式下载的源码,则无需解压,用 Visual Studio Code
直接打开源码存放位置下的 vue-next
文件夹。由于 git clone
方式下载下来的是整个仓库的代码,默认是 master
主分支版本,如果想切换成其它版本(比如当前最新的稳定版本 v3.1.4
),可以先在终端执行 git tag
命令查看都打包过哪些 tag
,再通过 git checkout v3.1.4
切换到 v3.1.4
版本(不切换的话,默认使用 master
也没有太大问题),然后执行 yarn install
后直接执行 yarn dev
(或 npm dev
)即可。
那跑起来后有什么用呢?用处就是我们可以在 script
标签中打上 debugger
进行调试啦:
比如,我们想看下 createApp
究竟做了些什么,就可以 F10
到 Vue.createApp
这行,再 F11
跳转进 createApp
函数:
但是,我们会发现这样做是在 vue.global.js
这个大文件中进行的调试,这意味着所有源代码都是放到了一起的,看起来非常不方便。那有没有办法让调试的时候跳转到某个具体的源代码文件中呢?有,我们可以修改项目目录下 package.json
文件中的 scripts
中的 dev
脚本对应的命令,在该命令最后添加上 --sourcemap
(webpack
相关的内容):
然后重新执行 yarn dev
把项目重新打包后跑起来(这时 dist
目录下会多出来一个 vue.global.js.map
文件,这个就是 sourcemap
文件,用来方便我们调试),这样一来,调试过程中的每一行代码都可以映射到它所在的具体文件中了,那么我们就能通过映射的文件和项目中的 packages
文件夹下的文件对应起来了:
写在最后
文中如有错误,欢迎大家在评论区指正。