0%

对象是包含一组键值对的实例。值可以是标量、函数、数组、对象等。

基本用法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
// ts
let obj = {
a: 'obj', // 标量
b: () => {}, // 函数
c: [1, 2, ,3], // 数组
d: { key01: 'a', key02: 'b' } // 对象
}
console.log(obj.a) // obj
console.log(obj.b()) // 我是函数
console.log(obj.c) // [1, 2, 3]
console.log(obj.d) // { key01: 'a', key02: 'b' }

// 编译成js后
var obj = {
a: 'obj', // 标量
b: function () { return '我是函数'; }, // 函数
c: [1, 2, 3], // 数组
d: { key01: 'a', key02: 'b' } // 对象
};
console.log(obj.a);
console.log(obj.b());
console.log(obj.c);
console.log(obj.d);

定义对象类型

匿名对象变量

匿名对象是在定义变量时直接使用花括号{},来定义一个对象类型。

1
const person: { name: string, age: number } = { name: '老王', age: 30 }

匿名对象函数

1
2
3
4
const personFn = (person: { name: string, age: number }) => {
console.log(`姓名:${person.name},年龄:${person.age}`)
}
personFn({ name: '老王', age: 30 }) // 姓名:老王,年龄:30

接口类型

从上面的例子可以看出,每次都这样写对象类型会很麻烦,如果遇到使用同一种对象类型的数据时,需要多次写入,增添了工作量。那么这个时候就可以使用接口来定义对象类型,使代码更加可读、易于维护。

1
2
3
4
5
6
7
8
9
interface Person {
name: string,
age?: number
}
const personFn = (person: Person) => {
if (person.age !== undefined) console.log(`姓名:${person.name},年龄:${person.age}`)
else console.log(`姓名:${person.name}`)
}
personFn({ name: '老王' }) // 姓名:老王

类型别名

类型别名用来给一个类型起个新名字,使用 type 创建类型别名,类型别名不仅可以用来表示基本类型,还可以用来表示对象类型、联合类型、元组和交集。

1
2
3
4
5
6
7
8
9
type Person = {
name: string,
age? : number
}
const personFn = (person: Person) => {
if (person.age !== undefined) console.log(`姓名:${person.name},年龄:${person.age}`)
else console.log(`姓名:${person.name}`)
}
personFn({ name: '老王' }) // 姓名:老王

属性修饰符

可选属性

对象类型还可以指定它们的部分或全部属性是可选的。为此,请在属性名称后添加 ?

比如我们在填写个人信息时,年龄一般会选择不填写。

1
2
3
4
const personFn = (person: { name: string, age?: number }) => {
console.log(`姓名:${person.name},年龄:${person.age}`)
}
personFn({ name: '老王' }) // 姓名:老王,年龄:undefined

从上面例子的结果可以看出,如果访问了一个不存在的属性age并不会运行错误,而是会返回undefined,所以当我们在读取可选属性中的数据时,尽量在使用这个属性之前检查一下,如下:

1
2
3
4
5
const personFn = (person: { name: string, age?: number }) => {
if (person.age !== undefined) console.log(`姓名:${person.name},年龄:${person.age}`)
else console.log(`姓名:${person.name}`)
}
personFn({ name: '老王' }) // 姓名:老王

只读属性

我们使用 readonly 关键字来声明只读属性,属性的值一旦被赋值就不能再次修改。

1
2
3
4
5
6
7
8
9
10
11
12
13
type Person = {
name: string,
readonly age: number,
readonly sex: string
}
const person: Person = {
name: '老王',
age: 30,
sex: '男'
}
person.name = '翠花'
person.age = 18 // 报错,只读属性一旦被赋值就不能再次修改
person.sex = '女' // 报错,只读属性一旦被赋值就不能再次修改

索引签名

有时你无法提前知道类型属性的所有名称,在这种情况下,你可以使用索引签名来描述可能值的类型。

  1. 基本用法
1
2
3
4
5
6
7
8
interface personInfo {
[key: string]: string | number
}
const person_info: personInfo = {
name: '老王',
sex: '男'
}
console.log(person_info) // { name: '老王', sex: '男' }
  1. 只读索引签名
1
2
3
4
5
6
7
8
9
interface personInfo {
readonly [key: string]: string | number
}
const person_info: personInfo = {
name: '老王',
age: 30,
sex: '男'
}
person_info.age = 18 // 报错
  1. 联合类型索引签名
1
2
3
4
5
6
7
8
9
interface personInfo {
[key: string]: string | number
}
const person_info: personInfo = {
name: '老王',
age: 30,
sex: '男'
}
console.log(person_info) // { name: '老王', age: 30, sex: '男' }

泛型对象类型

在我们还不知道是什么样子的对象类型时,可以使用 泛型 先占位,等知道后再补充。

1
2
3
4
5
6
7
8
9
10
11
interface Person<T> {
phone: T
}
const person01: Person<number> = {
phone: 13222222222
}
const person02: Person<string> = {
phone: '020-1111111'
}
console.log(person01) // { phone: 13222222222 }
console.log(person02) // { phone: '020-1111111' }

联合类型

联合类型使用 | 分隔每个类型,表示多种类型的联合。

  1. 变量使用联合类型
    比较常见的是电话号码,电话号码可以是手机号码,也可以是座机。其中手机号码是纯数字,座机是字符串,这个时候就可以使用联合类型了。
1
2
3
let phone: number | string = 13222222222
// 或者
let phone: number | string = '020-123456'
  1. 函数使用联合类型
1
2
3
4
5
6
function savePhone(phone: number | string) {
if (typeof phone === 'number') console.log('保存了手机号码')
else if (typeof phone === 'string') console.log('保存了座机')
}
savePhone(13222222222) // 保存了手机号码
savePhone('020-123456') // 保存了座机

交叉类型

交叉类型使用 & 分隔每个类型,是将多个类型合并为一个类型。

比如上一章接口说到的男人女人要怎么和人关联起来

1
2
3
4
5
6
7
8
9
10
11
12
13
14
interface Person {
name: string,
age: number
}
interface Sex {
sex: '男' | '女'
}
const sexFn = (info: Person & Sex) => {
console.log(info.name)
console.log(info.age)
console.log(info.sex)
}
sexFn({ name: '老王', age: 30, sex: '男' })
sexFn({ name: '翠花', age: 18, sex: '女' })

类型断言

类型断言Type Assertion可以收到指定一个类型,允许我们重写TypeScript数据的类型。

  1. 语法01:value as type
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
interface Cat {
run: () => void
}
interface Fish {
swim: () => void
}

// 以下方法会报错,虽然猫和鱼都是动物,但是鱼并不会奔跑,在动物调用时时没有run这个方法的。
// const isCat = (animal: Cat | Fish): boolean => {
// if (typeof animal.run === 'function') return true
// else return false
// }

// 所以应该在动物调用时给这个动物指定一个run的方法,如下:
const isCat = (animal: Cat | Fish): boolean => {
if (typeof (animal as Cat).run === 'function') return true
else return false
}

const cat: Cat = {
run() {}
}
console.log(isCat(cat)) // true

const fish: Fish = {
swim() {}
}
console.log(isCat(fish)) // false

  1. 语法02:<type>value
1
2
3
4
const isCat = (animal: Cat | Fish): boolean => {
if (typeof (<Cat>animal).run === 'function') return true
else return false
}

as const

const 声明的变量如果是基本类型,那么不允许改变,如果是引用类型,那么只要不改变引用的地址就是可以的。
举个例:

1
2
3
4
const a = 1
a = 2 // 报错
const b = [2, 3]
b.push(4) // 通过

那么如果使用as const断言会怎么样呢

1
2
3
4
5
let c = 5 as const
c = 6 // 报错

const d = [7, 8] as const
d.push(9) // 报错,因为此时变量d已经被断言字面量为[7, 8],数据无法再做任何修改

类型断言是不具影响力的

从下面的例子可以看出,虽然参数f通过了编译,但是并没有影响到最终的结果。因为在编译过程中,类型断言已经被删除了。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
// ts
function eFn(f: any): string {
return f as string
}

const g = eFn(true)
console.log(g) // true

// 编译成js后
function eFn(f) {
return f;
}
var g = eFn(true);
console.log(g); // true

注意

虽然使用类型断言可以指定一个类型,但是这样做只是避开了typeScript编译器的检测,在运行时还是有可能报错,所以在开发时应该避免滥用类型断言。

基础类型:布尔类型,数字类型,字符串类型,数组类型,null,undefined,never类型,空值类型,任意类型,unknown类型

布尔类型(boolean)

表示逻辑值:true 和 false

1
2
3
4
5
6
7
// ts
let a: boolean = true
let b: boolean = false

// 编译成js后
var a = true;
var b = false;

数字类型(number)

数字类型支持 二进制 八进制 十进制 十六进制 NaN Infinity

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// ts
let num_2: number = 11111101000 // 二进制
let num_8: number = 3750 // 八进制
let num_10: number = 2024 // 十进制
let num_16: number = 7e8 // 十六进制
let num_NaN: number = NaN // NaN
let num_Infinity: number = Infinity // 无穷大

// 编译成js后
var num_2 = 11111101000;
var num_8 = 3750;
var num_10 = 2024;
var num_16 = 7e8;
var num_NaN = NaN;
var num_Infinity = Infinity;

字符串类型(string)

一个字符系列,使用单引号(')或双引号(")来表示字符串类型。反引号(`)来定义多行文本和内嵌表达式。

1
2
3
4
5
6
7
8
9
// ts
let str_01: string = '我是字符串'
let str_02: string = `你好,${str_01}`
console.log(str_02) // 你好,我是字符串

// 编译成js后
var str_01 = '我是字符串';
var str_02 = "\u4F60\u597D\uFF0C".concat(str_01);
console.log(str_02);

数组类型

声明变量为数组。

使用方法01,类型[]

1
2
3
4
5
6
7
8
// ts
let arr_01:number[] = [1, 2, 3]
let arr_02:string[] = ['a', 'b', 'c']
// let arr_03:boolean[] = [false, true, 1, 'a'] // 这样会报错,因为布尔类型数组中出现了数字和字符串,这是不允许的

// 编译成js后
var arr_01 = [1, 2, 3];
var arr_02 = ['a', 'b', 'c'];

使用方法02,数组<类型>

1
2
3
4
5
6
7
// ts
let arr_04: Array<number> = [1, 2, 3]
let arr_05: Array<string> = ['a', 'b', 'c']

// 编译成js后
var arr_04 = [1, 2, 3];
var arr_05 = ['a', 'b', 'c'];

使用方法03,多维数组,类型[][]

1
2
3
4
5
// ts
let arr_06: number[][] = [[1, 2], [3, 4]]

// 编译成js后
var arr_06 = [[1, 2], [3, 4]];

使用方法04,使用接口表示数组

1
2
3
4
5
6
7
8
9
// ts
interface interfaceArr {
[key: number]: string
}
// 索引key的类型为数字类型时才可使用
let arr_07: interfaceArr = ['a', 'b', 'c']

// 编译成js后
var arr_07 = ['a', 'b', 'c'];

使用方法05,any数组

数组中的值可以是任意类型

1
2
3
4
5
// ts
let arr_08: any[] = [1, 'a', true, { b: '2', c: 3 }]

// 编译成js后
var arr_08 = [1, 'a', true, { b: '2', c: 3 }];

null类型

表示对象值缺失。

1
2
3
4
5
// ts
let null_01: null = null

// 编译成js后
var null_01 = null;

undefined类型

用于初始化变量为一个未定义的值

1
2
3
4
5
// ts
let undefined_01: undefined = undefined

// 编译成js后
var undefined_01 = undefined;

never类型

never 是其它类型(包括 null 和 undefined)的子类型,代表从不会出现的值。

1
let never_01: number & string = 1     // let never_01: never

以上代码会报错,因为numberstring是无法同时存的,所以never_01是never类型。

空值类型(void)

用于标识方法返回值的类型,表示该方法没有返回值

1
2
3
4
5
6
7
8
9
// ts
function voidFn(): void {
console.log('我是空值函数')
}

// 编译成js后
function voidFn() {
console.log('我是空值函数');
}

任意类型(any)

声明为 any 的变量可以赋予任意类型的值,没有强制限定哪种类型。

1
2
3
4
5
6
7
8
9
10
11
// ts
let any_01: any = 123
any_01 = 'abc'
any_01 = true
any_01 = [1, 2, 3]

// 编译成js后
var any_01 = 123;
any_01 = 'abc';
any_01 = true;
any_01 = [1, 2, 3];

注意:如果使用any就失去了ts类型检测的作用了,建议减少使用。

unknown类型

一种顶级类型,表示一个未知的值。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
// ts
let unknown_01: unknown
unknown_01 = 1
unknown_01 = 'a'
unknown_01 = true
unknown_01 = [1, 'a', true]
unknown_01 = { a: 1, b: 'c' }
unknown_01 = null
unknown_01 = undefined
unknown_01 = Symbol('type')

// 编译成js后
var unknown_01;
unknown_01 = 1;
unknown_01 = 'a';
unknown_01 = true;
unknown_01 = [1, 'a', true];
unknown_01 = { a: 1, b: 'c' };
unknown_01 = null;
unknown_01 = undefined;
unknown_01 = Symbol('type');

any类型 和 unknown类型 的区别

  1. unknow类型比any类型更严格,更安全。
  2. any类型表示任意类型,没有ts类型检查。unkonw类型是暂时未知类型,有ts类型检查。
  3. any是最宽的类型。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
// any,可以正常调用属性和方法,哪怕是未知的属性和方法也可以调用
let any_02: any = { a: 1, b: (): number => 2 }
any_02.a
any_02.b()
any_02.e
any_02.f()

// unknown,无法调用属性和方法
let unknown_02: unknown = { c: 3, d: (): number => 4 }
unknown_02.c
unknown_02.d()

// any是最宽的类型
type any_03 = unknown & any // any

介绍

什么是TypeScript

ts是js的超集,ts是一种基于js构建的强类型编程语言,可为你提供任何规模的更好工具,ts可以编译成纯js。

什么是超集

超集是包含一个较小集合的所有元素的集合,比如A的集合是[1,2,3],B的集合是[1],那么A就是B的超集。

安装

使用npm时需要有nodejs环境,可以前往node官网下载安装。

1
2
// 在终端执行以下代码安装typescript
npm install typescript -g

安装完成后可以在终端执行 tsc -v 查看版本号。

简单使用

新建一个文件夹,并在该文件夹中新建 index.ts 文件,在文件中输入

1
2
let a: number = 1
let b: boolean = false

输入完成后打开位于该文件夹位置的终端,并执行 tsc index.ts 即可在当前文件夹下生成index.js文件。

1
2
var a = 1;
var b = false;

如果觉得每次更新 index.ts 文件都需要手动编译太麻烦了, 可以在终端输入 tsc -w,这样每次更新后都会自动编译了。

算法

  • 线性搜索
  • 二分搜索
  • 深度优先搜索

总结

搜索算法高效查找。### 线性搜索
当列表未排序时,可从头到尾遍历查找。

二分搜索

适用于已排序数组,每次折半查找。复杂度 O(log n)。

深度优先搜索 (DFS)

图或树中递归深入每个分支。

广度优先搜索 (BFS)

按层次扩展节点,常用于最短路径。

应用示例

  • 网站搜索引擎
  • 树形结构遍历如文件系统

复杂度对比

  • 线性搜索 O(n)
  • 二分搜索 O(log n)
  • DFS/BFS O(V+E)

注意事项

  • 二分搜索要求有序
  • DFS 可能导致深度过大

FILLER_SEARCH_1
FILLER_SEARCH_2
FILLER_SEARCH_3
FILLER_SEARCH_4
FILLER_SEARCH_5
FILLER_SEARCH_6
FILLER_SEARCH_7
FILLER_SEARCH_8
FILLER_SEARCH_9
FILLER_SEARCH_10
FILLER_SEARCH_11
FILLER_SEARCH_12
FILLER_SEARCH_13
FILLER_SEARCH_14
FILLER_SEARCH_15
FILLER_SEARCH_16
FILLER_SEARCH_17
FILLER_SEARCH_18
FILLER_SEARCH_19
FILLER_SEARCH_20
FILLER_SEARCH_21
FILLER_SEARCH_22
FILLER_SEARCH_23
FILLER_SEARCH_24
FILLER_SEARCH_25
FILLER_SEARCH_26
FILLER_SEARCH_27
FILLER_SEARCH_28
FILLER_SEARCH_29
FILLER_SEARCH_30
FILLER_SEARCH_31
FILLER_SEARCH_32
FILLER_SEARCH_33
FILLER_SEARCH_34
FILLER_SEARCH_35
FILLER_SEARCH_36
FILLER_SEARCH_37
FILLER_SEARCH_38
FILLER_SEARCH_39
FILLER_SEARCH_40
FILLER_SEARCH_41
FILLER_SEARCH_42
FILLER_SEARCH_43
FILLER_SEARCH_44
FILLER_SEARCH_45
FILLER_SEARCH_46
FILLER_SEARCH_47
FILLER_SEARCH_48
FILLER_SEARCH_49
FILLER_SEARCH_50
FILLER_SEARCH_51
FILLER_SEARCH_52
FILLER_SEARCH_53
FILLER_SEARCH_54
FILLER_SEARCH_55
FILLER_SEARCH_56
FILLER_SEARCH_57
FILLER_SEARCH_58
FILLER_SEARCH_59
FILLER_SEARCH_60
FILLER_SEARCH_61
FILLER_SEARCH_62
FILLER_SEARCH_63
FILLER_SEARCH_64
FILLER_SEARCH_65
FILLER_SEARCH_66
FILLER_SEARCH_67
FILLER_SEARCH_68
FILLER_SEARCH_69
FILLER_SEARCH_70
FILLER_SEARCH_71
FILLER_SEARCH_72
FILLER_SEARCH_73
FILLER_SEARCH_74
FILLER_SEARCH_75
FILLER_SEARCH_76
FILLER_SEARCH_77
FILLER_SEARCH_78
FILLER_SEARCH_79
FILLER_SEARCH_80
FILLER_SEARCH_81
FILLER_SEARCH_82
FILLER_SEARCH_83
FILLER_SEARCH_84
FILLER_SEARCH_85
FILLER_SEARCH_86
FILLER_SEARCH_87
FILLER_SEARCH_88
FILLER_SEARCH_89
FILLER_SEARCH_90
FILLER_SEARCH_91
FILLER_SEARCH_92
FILLER_SEARCH_93
FILLER_SEARCH_94
FILLER_SEARCH_95
FILLER_SEARCH_96
FILLER_SEARCH_97
FILLER_SEARCH_98
FILLER_SEARCH_99
FILLER_SEARCH_100
FILLER_SEARCH_101
FILLER_SEARCH_102
FILLER_SEARCH_103
FILLER_SEARCH_104
FILLER_SEARCH_105
FILLER_SEARCH_106
FILLER_SEARCH_107
FILLER_SEARCH_108
FILLER_SEARCH_109
FILLER_SEARCH_110

Vite 是什么?

Vite 是快速前端构建工具,基于 ES modules。

创建项目

1
npm create vite@latest my-app

开发服务器

1
2
3
4
5
6
7
8
// vite.config.js
import { defineConfig } from 'vite'

export default defineConfig({
server: {
port: 3000
}
})

构建配置

1
2
3
4
5
6
export default defineConfig({
build: {
outDir: 'dist',
minify: 'terser'
}
})

插件

1
2
3
4
5
import vue from '@vitejs/plugin-vue'

export default defineConfig({
plugins: [vue()]
})

CSS 预处理

1
2
3
4
5
6
7
8
9
export default defineConfig({
css: {
preprocessorOptions: {
scss: {
additionalData: `@import "src/styles/variables.scss";`
}
}
}
})

环境变量

1
2
3
4
5
// .env
VITE_API_URL=https://api.example.com

// 使用
console.log(import.meta.env.VITE_API_URL)

总结

Vite 开发体验优秀。快如闪电的热重载。

前言

到目前为止,vue-cli 项目基本已经完成了,那么现在我们只剩最后一步了,那就是怎么将项目进行打包并放进服务器中。

首先

在 vue-cli 项目根目录中打开 cmd 命令行工具,执行命令:npm run build后命令行工具会开始处理。

然后

当执行完成后,我们可以看到项目根目录中多了一个名为dist的文件夹,打开一看,可以看到很多我们熟悉的东西,比如index.htmlcssjs等,没错了,这个就是打包后生成的文件了,我们只需要将这一份代码放进服务器中即可。

注意

在执行打包命令时,有时会报一些错误,比如:

1
To install it, you can run: npm install --save vue-router

这是因为vue-router没有找到,需要重新安装,我们在命令行工具执行npm install --save vue-router即可。安装完成后再次尝试进行打包。

如果还是失败,我们可以尝试将node_modules文件夹删除掉,然后再次执行npm install安装依赖。

一般情况下,项目能正常启动的话,打包时是不会报错的,如果报错了,按照报错提示进行修改即可。

介绍

Axios 是一个基于 promise 的 HTTP 库,可以用在浏览器和 node.js 中。

特征

  1. 从浏览器中创建 XMLHttpRequests
  2. 从 node.js 创建 http 请求
  3. 支持 Promise API
  4. 拦截请求和响应
  5. 转换请求数据和响应数据
  6. 取消请求
  7. 自动转换 JSON 数据
  8. 客户端支持防御 XSRF

安装

vue-cli项目根目录中打开cmd窗口,输入命令:

1
npm install axios

简单使用

模版代码:

1
2
3
axios.get(url)
.then((res) => { })
.catch((err) => { })

打开v-news.vue文件,完整代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
<template>
<div class="v-news content">
<ul>
<li v-for="item in lists" :key="item.id">
<router-link :to="{ name: 'detail', params: { id: item.time } }">{{ item.title }}</router-link>
</li>
</ul>
</div>
</template>

<script>
// 引入 axios
import axios from 'axios';

export default {
name: 'v-news',
desc: '新闻列表',
data() {
return {
lists: []
}
},
created() {
axios.get('/news/lists')
.then((res) => {
this.lists = res.data;
})
}
}
</script>

使用完成,在浏览器中运行查看效果,可以看到数据正常显示。

总结

axios的请求方式不仅仅有get,还有其他的,比如postdelete等,在本章使用了get,如果大家想了解更多,可以在网上查看axios使用文档。

前后分离的开发流程

  1. 项目需求分析
  2. 前端和后台商量所需接口数据
  3. 前端和后台各自开发
  4. 前端对接接口,此时后台很大可能是还没有开发完接口,所以前端需要按照第二步所商量的结果模拟数据
  5. 后台开发接口完成,开始联调
  6. 如果调试没有任何问题,将项目提交至测试环境交给测试人员进行测试
  7. 根据测试文档进行让人头疼的 bug 修改
  8. 测试通过,项目正式发布

什么是 mock.js

生成随机数据,拦截 Ajax 请求

在第一节中提到了需要模拟一些假数据,那么该怎么模拟呢?很多人可能会说直接在页面书写点数据就好了。这样做也是可以的,但是太麻烦了,不规范,虽然前期能够快速完成开发,但是后期对接完接口后需要对这些假数据进行删除是一件令人头疼的事。

简单使用

安装

首先打开vue-cli项目,然后在项目根目录下打开cmd窗口,输入指令npm install mockjs进行安装

模拟

src文件夹下新建名称为mock.js的文件,用于生成模拟数据。完整代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
// 引入mockjs
import Mock from 'mockjs';
// Mock.Random 是一个工具类,用于生成各种随机数据
const Random = Mock.Random;
let data = [];
for(let i = 0; i < 10; i ++) {
data.push({
title: Random.title(),
time: Random.datetime()
})
}

// 模拟新闻列表
Mock.mock('/news/lists', 'get', data);

引用

打开main.js文件并进行引用,完整代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
import Vue from 'vue'
import App from './App.vue'

// 引入我们配置好的路由
import router from './router';

Vue.config.productionTip = false

// 引入样式
import './assets/css/app.css';

// 引入 mock 模拟数据
require('./mock');

new Vue({
router,
render: h => h(App),
}).$mount('#app')

mock.js 的优点

通过上面的简单使用,我们能直观体会到的优点有:

  1. 让前端工程师独立于后端进行开发
  2. 通过随机数据,模拟各种场景
  3. 符合直觉的接口
  4. 支持生成随机的文本、数字、布尔值、日期、邮箱、链接、图片、颜色等

总结

其实在敲代码时,我们可以发现mock.js其实是一个很好玩的东西,完全没有想象中的那么麻烦,当后台提供了接口后,我们只需要把在main.js的引用去掉就可以开始和后台进行联调了,简直不要太方便了。
那么,我们应该如何在v-news.vue文件中使用ajax请求模拟的新闻列表数据呢?请看下一章。

一,前言

我们经常会一边开发项目,一边调整项目。比如现在我们把所有的组件都放在了components文件夹下面,如果后期我们需要修改组件的路径,那么问题就来了,比如我需要修改v-about.vue文件的路径,那么我们就需要修改v-header.vuerouter -> index.js文件对应的路径。如果只是修改一个文件路径,问题倒不大,可是如果我们需要修改十几个或更多组件的路径,这就很头疼了。那么怎么解决这个问题呢?你可以在创建 Router 实例的时候,在 routes 配置中给某个路由设置名称。

模版代码:

1
2
3
4
5
6
7
8
9
const router = new VueRouter({
routes: [
{
path: '/user/:userId',
name: 'user',
component: User
}
]
})

其实就是在路由配置时,给该组件加了一个name

二,开始尝试

我们现在components文件夹下新建一个名称为content的文件夹,然后将v-about.vuev-index.vuev-news.vuev-news-detail.vue等四个文件放到content文件夹中。

当修改了路径后,大家可以看到cmd窗口开始报错,vue-cli项目在浏览器中打开是一片空白,什么都没有。

目前项目目录结构如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
.
|-- node_modules
|-- public
| |-- favicon.ico
| |-- index.html
|-- src
| |-- assets
| | |-- css
| | | |-- app.css
| |-- components
| | | |-- content
| | | | |-- v-about.vue
| | | | |-- v-index.vue
| | | | |-- v-news-detail.vue
| | | | |-- v-news.vue
| | |-- HelloWorld.vue
| | |-- v-header.vue
| | |-- v-success.vue
| |-- router
| | |-- index.js
| |-- App.vue
| |-- main.js
|-- .gitignore
|-- babel.config.js
|-- package-lock.json
|-- package.json
|-- README.md
.

修改路由配置

打开router -> index.js文件添加name

修改后的完整代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
// 引入 Vue
import Vue from 'vue';
// 引入 vue-router
import VueRouter from 'vue-router';
// 安装使用 vue-router
Vue.use(VueRouter);
// 引入首页
import vIndex from '../components/content/v-index.vue';
// 开始使用 vue-router
let routes = new VueRouter({
routes: [
{
path: '/',
name: 'index',
component: vIndex
},
{
path: '/about',
name: 'about',
component: () => import(/* webpackChunkName: "about" */ '../components/content/v-about.vue')
},
{
path: '/success',
component: () => import(/* webpackChunkName: "success" */ '../components/v-success.vue')
},
{
path: '/news',
name: 'news',
component: () => import(/* webpackChunkName: "news" */ '../components/content/v-news.vue')
},
{
path: '/news/:id',
name: 'detail',
component: () => import(/* webpackChunkName: "news" */ '../components/content/v-news-detail.vue')
},
]
});
// 提供接口给外面使用
export default routes;

接着打开v-header.vue文件修改router-link中的to

修改后的完整代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
<template>
<div class="v-header">
<ul class="menus">
<li
class="menu"
v-for="item in menus"
:key="item.id"
>
<router-link :to="{ name: item.path }">{{ item.name }}</router-link>
</li>
</ul>
</div>
</template>

<script>
export default {
name: 'v-header',
desc: '头部信息',
data() {
return {
menus: [
{ id: 1, name: '首页', path: 'index' },
{ id: 2, name: '新闻', path: 'news' },
{ id: 3, name: '关于', path: 'about' },
]
}
}
}
</script>

<style scoped>
.v-header {
width: 100%;
height: 70px;
background-color: #fff;
box-shadow: 3px 3px 3px #ddd;
color: #333;
}
.menus {
list-style: none;
padding: 0 20px;
overflow: hidden;
}
.menu {
float: left;
padding: 0 20px;
height: 70px;
line-height: 80px;
transition: .3s;
}
.menu:hover {
cursor: pointer;
color: #0051ff;
background-color: #efefef;
}
</style>

最后再打开v-news.vue文件修改router-link中的to

修改后的完整代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
<template>
<div class="v-news content">
<ul>
<li v-for="item in lists" :key="item.id">
<router-link :to="{ name: 'detail', params: { id: item.id } }">{{ item.title }}</router-link>
</li>
</ul>
</div>
</template>

<script>
export default {
name: 'v-news',
desc: '新闻列表',
data() {
return {
lists: [
{ id: 1, title: '新闻标题 1' },
{ id: 2, title: '新闻标题 2' },
{ id: 3, title: '新闻标题 3' },
{ id: 4, title: '新闻标题 4' },
{ id: 5, title: '新闻标题 5' },
{ id: 6, title: '新闻标题 6' },
]
}
}
}
</script>

到目前位置,代码已经修改完成了,可以在浏览器中打开看看效果。如果再次发生组件的路径改变,那么我们只需要直接修改router -> index.js文件即可。

三,总结

希望大家能敲一遍代码,体验修改的繁琐和添加命名路由的方便,这样在以后开发时,就会考虑到底要使用path还是name。如果大家需要vue-cli项目源码,可以私信我哈。