学习不一样的vue4:mock与axios实战2

首先

今天的任务

  • 完成代办单项列表的新页面
  • 利用vue-router访问到代办单项页面
  • 利用 mockjs模拟2个接口,一个待办单项列表查询,一个是新增待办单项
  • 利用axios请求数据进行交互

新增src/components/todo.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
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
57
58
59
60
61
62
63
64
65
66
<template>
<div class="page lists-show">
<!-- 头部模块 -->
<nav>
<!-- 当用户浏览车窗口尺寸小于40em时候,显示手机端的菜单图标 -->
<div class="nav-group">
<a class="nav-item">
<span class="icon-list-unordered">
</span>
</a>
</div>
<!-- 显示标题和数字模块 -->
<h1 class="title-page">
<span class="title-wrapper">{{todo.title}}</span> <!-- title:标题 绑定标题 -->
<span class="count-list">{{todo.count || 0}}</span><!-- count:数量 绑定代办单项熟练-->
</h1>
<!-- 右边显示删除图标和锁定图标的模块 -->
<div class="nav-group right">
<div class="options-web">
<a class=" nav-item">
<!-- cicon-lock锁定的图标
icon-unlock:非锁定的图标
-->
<span class="icon-lock" v-if="todo.locked"></span>
<span class="icon-unlock" v-else>
</span>
</a>
<a class=" nav-item">
<span class="icon-trash">
</span>
</a>
</div>
</div>
<!-- 用户新增代办事项的input模块 -->
<div class=" form todo-new input-symbol">
<!-- 绑定disabled值,当todo.locked为绑定的时候,禁止input输入 -->
<input type="text" v-model="text" placeholder='请输入' :disabled="todo.locked" />
<span class="icon-add"></span>
</div>
</nav>
<!-- 列表主体模块 -->
<div class="content-scrollable list-items">
</div>
</div>
</template>
<script>
export default {
data() {
return {
todo: {
title: '星期一', //标题
count: 12, //数量
locked: false //是否绑定
},
items: [ //代办单项列表
],
text: '' //用户输入单项项绑定的输入
}
}
}
</script>
<style lang = "less">
@import '../common/style/nav.less';
@import '../common/style/form.less';
@import '../common/style/todo.less';
</style>

修改router

新增知识点(必读)

打开src/router/index.js

替换以下代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
...
...
export default new Router({
routes: [{
path: '/',
name: 'Layouts',
component: Layouts,
children: [{
path: '/todo/:id',
name: 'todo',
component: todo
}]
}]
})

新加watcher

新增知识点(必读)

打开 src/components/menus.vue

1
2
3
4
5
6
7
8
9
10
export default {
...
watch: {
'todoId'(id) {
this.$router.push({ name: 'todo', params: { id: id } });
//监听到用户的点击todoId的变化在跳转路由
}
},
...
}

最后,浏览器浏览localhost:7070,你将会看到下面的页面.

新增mock数据与api接口

mockDate

打开src/mock/mock.js

新增todo单个列表查询
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
// 获取todo单个列表
export default {
start() {
...
mock.onGet('/todo/listId').reply(config => {
let {
id
} = config.params;
// id 是传进来的值
// todo 是根据id和现有的Todos数据匹配,找出id相等的数据,在进行返回
let todo = Todos.find(todo => {
return id && todo.id === id;
});
// todo.count (等待完成数目)等于 todo.record(代办事项列表下面未被选择的数据
todo.count = todo.record.filter((data) => {
return data.checked === false;
}).length;
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve([200, {
todo: todo
}]);
}, 200);
});
});
...
}
新增一条代办事项新增
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
// 新增一条代办事项
export default {
start() {
...
mock.onPost('/todo/addRecord').reply(config => {
let {
id,
text
} = JSON.parse(config.data);
// id 是传进来的值唯一待办项的id
// text 用户新增输入的数据
Todos.some((t, index) => {
if (t.id === id) {
t.record.push({
text: text,
isDelete: false,
checked: false
});
return true;
}
});
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve([200]);
}, 200);
});
});
...
}

api.js

打开src/api/api.js
新增
1
2
3
4
5
6
7
8
9
10
11
12
...
//新增一个请求查询代办单项列表的数据的接口函数
export const getTodo = params => {
return axios.get(`/todo/listId`, {
params: params
});
};
//新增一个请求新增代办单的接口函数
export const addRecord = params => {
return axios.post(`/todo/addRecord`, params).then(res => res.data);
};
...

新增 Item.vue(src/components/Item.vue)

新增知识点(必读)

  • Prop(Prop主要用作父子组件之间的通信,必须掌握)
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
<template>
<div class="list-item editingClass editing">
<label class="checkbox">
<input type="checkbox" v-model="item.checked">
<span class="checkbox-custom"></span>
</label>
<input type="text" v-model="item.text" placeholder='写点什么。。。'>
<a class="delete-item">
<span class="icon-trash"></span>
</a>
</div>
</template>
<script>
// item 是todo的子组件,他接受一个对象item,来进行处理
export default {
props: {
item: {
type: Object,
default: () => {
return {
checked: false,
text: '你好,世界''
}
}
}
}
};
</script>
<style lang="less">
@import '../common/style/list-items.less';
</style>

使用组件

打开src/components/todo.vue

引入组件
1
2
3
4
5
<script>
// 引入组件
import item from './item';
...
</script>
挂载组件
1
2
3
4
5
6
7
8
9
10
11
12
<script>
//挂载组件
...
export default {
...
//components的作用就可以把其他子组件挂载到当前父组件的作用域里。
components: {
item
}
}
...
</script>
使用组件
1
2
3
4
5
6
7
<template>
...
<div class="content-scrollable list-items">
<item></item>
</div>
...
</template>

如果你看到下面的页面,哪么Item.vue组件就使用成功了。

调用接口

前面我们已经写好了模拟接口,和接口调用的函数,和完成了页面样式。下面完成最重要的接口调试部分。

新增知识点(必读)

  • 路由信息对象(它是object(路由信息对象) 表示当前激活的路由的状态信息,包含了当前 URL 解析得到的信息,还有 URL 匹配到的 route records(路由记录),必须了解)

使用查询接口列表的接口(getTodo)

打开 src/components/todo.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
31
32
33
34
35
36
37
38
...
import { getTodo} from '../api/api';
export default {
...
watch: {
'$route.params.id'() {
// 监听$route.params.id的变化,如果这个id即代表用户点击了其他的待办项需要重新请求数据。
this.init();
}
},
created() {
// created生命周期,在实例已经创建完成,页面还没渲染时调用init方法。
this.init();
},
methods: {
init() {
// 获取到 $route下params下的id,即我们在menus.vue组件处传入的数据。
const ID = this.$route.params.id;
getTodo({ id: ID }).then(res => {
let { id, title, count, isDelete, locked, record
} = res.data.todo;
// 请求成功,拿到res.data.todo;在将record 赋值到代办单项列表,其它数据赋值到todo对象
this.items = record;
this.todo = {
id: id,
title: title,
count: count,
locked: locked,
isDelete: isDelete
};
});
}
}
...
}
...
1
2
3
4
5
6
7
8
9
<template>
...
<div class="content-scrollable list-items">
<div v-for="item in items">
<item :item="item"></item>
</div>
</div>
...
</template>

如果你的页面能完成如下操作,那么这一步你就完成了。

使用新增代办单项接口(addRecord)

打开 src/components/todo.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
<template>
..
<div class=" form todo-new input-symbol">
<!-- 绑定disabled值,当todo.locked为绑定的时候,禁止input输入,双向绑定text,和监听input的回车事件@keyup.enter -->
<input type="text" v-model="text" placeholder='请输入' @keyup.enter="onAdd" :disabled="todo.locked" />
<span class="icon-add"></span>
</div>
...
</template>
...
import { getTodo, addRecord } from '../api/api';
export default {
...
methods: {
onAdd() {
//当用户输入文字,并且回车时调用次方法。
const ID = this.$route.params.id;
addRecord({ id: ID, text: this.text }).then(res => {
this.text = '';
this.init();
//请求成功后初始化
});
}
}
...
}

如果可以进行如下操作,那么这一步就成功了