扩展
环境搭建
安装脚手架
vue cli
1# 安装vue cli脚手架
2npm install -g @vue/cli
3# 升级vue cli脚手架版本
4npm update -g @vue/cli
5
6#查看vue版本
7vue --version
8vue -V
9
10# 命令行创建项目
11vue create project_name
12vue create . # 当前目录下创建
13# 可视化创建项目
14vue ui
创建项目
1# 命令行创建项目
2vue create project_name
3# 当前目录下创建
4vue create .
5
6# 1.选择手动选择功能并回车
7Vue CLI v5.0.8
8? Please pick a preset:
9 Default ([Vue 3] babel, eslint)
10 Default ([Vue 2] babel, eslint)
11❯ Manually select features
12
13# 2.按空格选中或取消选中,按回车下一步
14Vue CLI v5.0.8
15? Please pick a preset: Manually select features
16? Check the features needed for your project: (Press <space> to select, <a> to toggle all, <i> to invert selection, and <enter> to proceed)
17 ◉ Babel
18 ◯ TypeScript
19 ◯ Progressive Web App (PWA) Support
20 ◉ Router
21 ◉ Vuex
22 ◉ CSS Pre-processors
23❯◉ Linter / Formatter
24 ◯ Unit Testing
25 ◯ E2E Testing
26
27# 3.选择Vue版本,选择2.x并回车
28Vue CLI v5.0.8
29? Please pick a preset: Manually select features
30? Check the features needed for your project: Babel, Router, Vuex, CSS Pre-processors, Linter
31? Choose a version of Vue.js that you want to start the project with
32 3.x
33❯ 2.x
34
35# 4.是否使用history模式的路由,输入Y并回车
36Vue CLI v5.0.8
37? Please pick a preset: Manually select features
38? Check the features needed for your project: Babel, Router, Vuex, CSS Pre-processors, Linter
39? Choose a version of Vue.js that you want to start the project with 2.x
40? Use history mode for router? (Requires proper server setup for index fallback in production) (Y/n) Y
41
42# 5.选择css预处理器,选择Less并回车
43? Pick a CSS pre-processor (PostCSS, Autoprefixer and CSS Modules are supported by default):
44 Sass/SCSS (with dart-sass)
45❯ Less
46 Stylus
47
48# 6.选择ESLint,选择默认并回车
49? Pick a linter / formatter config: (Use arrow keys)
50❯ ESLint with error prevention only
51 ESLint + Airbnb config
52 ESLint + Standard config
53 ESLint + Prettier
54
55# 7.在什么时候检测Lint,选择默认并回车
56? Pick additional lint features: (Press <space> to select, <a> to toggle all, <i> to invert selection, and <enter> to proceed)
57❯◉ Lint on save
58 ◯ Lint and fix on commit
59
60# 8.将这个配置文件放在哪里?选择默认并回车
61? Where do you prefer placing config for Babel, ESLint, etc.? (Use arrow keys)
62❯ In dedicated config files
63 In package.json
64
65# 9.是否保存刚才的预设,(将刚才的配置作为模版,下次选择可直接创建,免去从头到尾一项一项配置的烦恼)
66 Save this as a preset for future projects? (y/N) N
67
68# 10.若9选择Y,这里需要为预设模版起名字
69 Save preset as:
启动项目
1cd project_name && npm run serve
环境变量
我们实际开发中,往往有多种环境,如
- development模式用于 vue-cli-service serve
- production模式用于vue-cli-service build 和 vue-cli-service test:e2e
- test模式用于vue-cli-service test:unit
甚至还有其他的,这里我们只讨论development和production。
此处有几个需要注意的点:
1.一个模式可以包含多个环境变量
2.每个模式都会将环境变量中 NODE_ENV 的值设置为模式的名称
3.可以通过.env文件增加后缀来设置某个模式下特有的环境变量
4.为一个特定模式准备的环境文件(例如 .env.production)将会比一般环境文件(例如 .env)拥有更高的优先级
1.env # 在所有环境中被载入
2.env.local # 在所有环境中被载入,但会被 git 忽略
3.env.[mode] # 只在指定的模式中被载入,优先级高于 .env 和 .env.local
4.env.[mode].local # 只在指定的模式中被载入,但会被 git 忽略,优先级高于 .env 和 .env.local
一般环境变量文件都创建在根目录下,我们创建以下两份:
.env.development
文件:
NODE_ENV=development
VUE_APP_BASE_URL=/
.env.production
文件:
NODE_ENV=production
VUE_APP_BASE_URL='http://www.xiaosutongxue.com'
使用场景
1const { defineConfig } = require('@vue/cli-service')
2module.exports = defineConfig({
3 devServer:{
4 // 在Vue中通过process.env.变量名获取环境变量
5 // 使用机制:当项目以生产环境启动时,process.env.VUE_APP_BASE_URL这个值就在.env.production文件中寻找
6 proxy: process.env.VUE_APP_BASE_URL
7 }
8})
怎么以生产环境启动呢?
配置 package.json
中的启动命令
1"scripts": {
2"serve": "vue-cli-service serve --mode production",
3"build": "vue-cli-service build"
4}
@路径配置
vscode安装 Path Intellisense
插件
打开设置-首选项-搜索 Path Intellisense
-打开 settings.json
,添加
1"path-intellisense.mappings":{
2 "@": "${workspaceRoot}/src"
3}
在项目 package.json
所在同级目录下创建文件 jsconfig.json
1{
2 "compilerOptions": {
3 "target": "ES6",
4 "module": "commonjs",
5 "allowSyntheticDefaultImports": true,
6 "baseUrl": "./",
7 "paths": {
8 "@/*": ["src/*"]
9 }
10 },
11 "exclude": [
12 "node_modules"
13 ]
14}
代码片段
1{
2 "vue2": {
3 "prefix": "v2",
4 "body": [
5 "<template>",
6 "\t<div>\n",
7 "\t</div>",
8 "</template>\n",
9 "<script>",
10 "export default {",
11 "\tdata() {",
12 "\t\treturn {\n",
13 "\t\t}",
14 "\t},",
15 "\tcomponents: {\n",
16 "\t},",
17 "\tcomputed: {\n",
18 "\t},",
19 "\tcreated() {\n",
20 "\t},",
21 "\tmethods: {\n",
22 "\t},",
23 "}",
24 "</script>\n",
25 "<style lang=\"less\" scoped>",
26 "</style>"
27 ]
28 }
29}
Vue2双向绑定原理
Object.defineProperty()
是ES5中一个无法shim的特性,可以用来给对象设置属性
一个shim是一个库,它将一个新的API引入到一个旧的环境中,而且仅靠旧环境中已有的手段实现。
比如:google和github上都有一段用于兼容ie等低版本浏览器的html标签库 html5shiv,ps: shim有时也叫shiv。
第一种方法:
1let obj = {
2 name: "xiaosutongxue"
3}
4
5// 普通添加属性的方式
6obj.age = 27
7
8// Object.defineProperty()添加属性的方式
9Object.defineProperty(obj, "wish", {
10 value: "code better",
11 writable: true, // 设置obj的wish属性可以被修改,默认值是false,不可被修改
12 configurable: true, // 设置obj的wish属性可以被删除,默认是false,不可被删除
13 enumerable: true // 设置obj的wish属性可以被遍历,默认是false,不可被遍历
14});
15
16console.log(obj)
第二种方法:
1let obj = {};
2let val = 10;
3Object.defineProperty(obj, "name", {
4 // 思考:此处get()什么时候执行,执行后返回了什么?
5 get() {
6 // 当获取name属性的时候,会执行这里的代码
7 console.log("get执行了");
8 // return返回的数据就是obj.name的值
9 return val;
10 },
11 set(newValue) {
12 // 当给name属性赋值的时候,会执行这里的代码
13 console.log("set执行了", newValue);
14 // 将新数据赋值给val,这样下次执行get()时,返回的就是新值
15 val = newValue;
16 },
17});
18
19console.log(obj.name); // 执行get()
20obj.name = "Vue"; // 触发set()
21console.log(obj.name); // 执行get()
22
23/** 控制台打印结果
24* get执行了
25* 10
26* set执行了 Vue
27* get执行了
28* Vue
29*/
模拟双向绑定
1<input type="text" id="inp" />
2<p id="pp"></p>
1// 准备一个对象,模拟data这个对象,往里面添加一个txtVal属性
2let obj = {};
3let val = "初始值";
4Object.defineProperty(obj, "txtVal", {
5 get() {
6 return val;
7 },
8 set(newValue) {
9 // 在set方法进行数据劫持
10 // 此处set()是第三方,负责通知每一个订阅者改数据了
11 inp.value = newValue;
12 pp.innerHTML = newValue;
13 val = newValue;
14 },
15});
16
17// 两个订阅者,都订阅了obj.txtVal
18inp.value = obj.txtVal;
19pp.innerHTML = obj.txtVal;
20
21// v-model可以用value属性和input事件代替
22inp.addEventListener("input", (e) => {
23 // 一边输入的时候,一边修改txtVal的值
24 // obj.txtVal = 用户输入的值
25 // 这里是发布者,发布新的数据
26 obj.txtVal = e.target.value; // 触发set()
27});
双向绑定原理
借助Object.defineProperty()的set()对数据进行劫持,并结合发布-订阅者模式来实现双向绑定
Vue2的数组内元素的修改失效问题
为什么会有这种bug
原理:Vue2的双向数据绑定原理用的是Object.defineProperty(),修改引用类型的数据(数组和对象)的时候没有办法触发set,所以最终导致的现象就是数据能够修改,但是界面修改不了。
Vue提供了 this.$set()
方法,可以用来修改引用类型的数据,同时进行界面修改。
this.$set(数组名,要修改元素的下标,新的值)
SPA
Single Page Application,中文:单页应用。
其实SPA最主要的特点就是在前后端分离的基础上加了一层前端路由,也就是前端来维护一套路由规则。
前端路由的核心是什么呢?
改变URL,但是页面不进行整体的刷新
MVVM
1.view层---body内的标签
视图层,在前端里面就是我们常说的DOM层,主要作用是给用户展示各种信息
2.Model层---new Vue对象
数据层,数据可能是我们自定义的数据,或者是从网络请求下来的数据
3.ViewModel层---vue.js文件
视图模型层,是view层和model层沟通的桥梁;
一方面它实现了数据绑定,将model的改变实时反应到view中;另一方面它实现了DOM监听,当DOM发生改变可以对应改变数据(Data)
scoped的作用
scoped会在元素上添加唯一的属性(data-v-x形式),css编译后也会加上属性选择器,从而达到限制作用域的目的
模块化
AMD、CMD,鼻祖级别的,现在半淘汰状态了
模块化目前比较流行的就是 CommonJs规范
和 ES6模块化
Commonjs
导出是导出,导入是导入两者没有必然关系
只要导出正确,导入使哪种方式都行,但尽量配套使用
导出
1var num = 10;
2var obj = {username:"su"}
3function func(){
4 return 123
5}
6
7//整体导出,支持对象简写
8module.exports = {
9 num,
10 obj,
11 func
12}
13
14//按需导出 不建议这么写,意义不大
15module.exports.num = num;
16module.exports.obj = obj;
17module.exports.func = func;
导入
1//commonjs
2var test = require('@/路径')
3//es6
4import test from '@/路径'
module.exports导出,本质上是在导出什么?
在导出exports
只写module 或者 module.exports;导出都是一个空对象,因为引入一个js文件,本质上就是在引入一个空对象
{
module:{
exports:{
num,
obj,
func
}
}
}
ES6
导出
1var num = 10;
2var obj = {username:"su"}
3function func(){
4 return 123
5}
6
7//整体导出
8export default {
9 num,
10 obj,
11 func
12}
13
14//按需导出,
15export var num = 10;
导入
1//es6 默认引入export下的default
2import test from '@/路径'
3
4//commonjs 默认引入的是export对象
5var test = require('@/路径')
6
7
8//按需导入
9import {num} from '@/路径'
export
:通过export方式导出,在导入的时候需要加,且不能换名字(导出啥名,导入就啥名,名字加到)
import {aaa,bbb,ccc导出的时候的名字} from "路径+文件名"
export default
:通过export default方式导出,导入时不需要加
- 使用场景
- 导出单个值就用
export default
- 导出多个值就用
export