3-02-案例-todolist

效果展示

创建项目

1
2
3
4
5
6
7
npm init vite-app todolist

cd todolist

npm i

npm i less -D

将Boostrap相关文件复制到static/css文件夹下面

在index.css中设置全局样式:

1
2
3
4
5
6
7
8
9
10
11
:root {

font-size: 12px;

}

body {

padding: 8px;

}

实现todo-list组件

  1. 初步实现components/todo-list.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
<template>

<ul class="list-group">

<li class="list-group-item d-flex justify-content-between
align-items-center">

<div class="custom-control custom-checkbox">

<input type="checkbox" class="custom-control-input" />

<label class="custom-control-label" ></label>

</div>

<span class="badge badge-success badge-fill">已完成</span>

<span class="badge badge-warning badge-fill">未完成</span>

</li>

</ul>

</template>

<style lang="less" scoped>

.list-group {

width: 400px;

}

</style>
  1. 在App.vue中定义数据,并传入todo-list中:
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
<template>

<div>

<todo-list :list="todolist"></todo-list>

</div>

</template>

<script>

import TodoList from './components/todolist.vue';

export default {

components: {

TodoList

},

data() {

return {

todolist: [

{

id: 1,

content: "周一早上8点开会"

},

{

id: 2,

content: "周一下午面试"

},

{

id: 3,

content: "周二下午发版本"

}

]

}

}

}

</script>
  1. 将传入的数据渲染到组件上面:
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
<template>

<ul class="list-group">

<li class="list-group-item d-flex justify-content-between
align-items-center" v-for="item in list" :key="item.id">

<div class="custom-control custom-checkbox">

<input class="custom-control-input" type="checkbox" :id="item.id"
/>

<label class="custom-control-label" :for="item.id" >{{
item.content }}</label>

</div>

<span class="badge badge-success badge-fill"
v-if="!item.done">未完成</span>

<span class="badge badge-warning badge-fill" v-else>已完成</span>

</li>

</ul>

</template>

<script>

export default {

props: {

list: {

type: Array,

required: true,

default: []

}

}

}

</script>
  1. 点击勾选框之后切换完成状态
1
2
3
4
5
6
...

<input class="custom-control-input" type="checkbox" :id="item.id"
v-model="item.done" />

...
  1. 增加删除特效
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
...

<label class="custom-control-label" :for="item.id"
:class="item.done ? 'delete' : ''">{{ item.content }}</label>

...

<style>

.delete {

font-style: italic;

color: #ccc;

text-decoration: line-through;

}

</style>

实现todo-input组件

  1. 实现todo-input.vue
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
<template>

<form class="form-inline">

<div class="input-group mb-2 mr-sm-2">

<div class="input-group-prepend">

<div class="input-group-text">任务</div>

</div>

<input class="form-control" type="text"
placeholder="请填写任务信息" style="width: 350px;" />

</div>

<button class="btn btn-primary mb-2">添加新任务</button>

</form>

</template>
  1. 点击添加按钮将数据刷新到列表中
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
<template>

<form class="form-inline" @submit.prevent="onFormSubmit">

<div class="input-group mb-2 mr-sm-2">

<div class="input-group-prepend">

<div class="input-group-text">任务</div>

</div>

<input class="form-control" type="text"
placeholder="请填写任务信息" style="width: 350px;"
v-model="taskContent"/>

</div>

<button class="btn btn-primary mb-2">添加新任务</button>

</form>

</template>

<script>

export default {

data() {

taskContent: ""

},

methods: {

onFormSubmit() {

this.$emit('addTask', this.taskContent);

}

}

}

</script>
  1. 在App.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
<template>

...

<todo-input @addTask="addNewTask"></todo-input>

...

</template>

<script>

import TodoInput from './components/todu-input.vue';

export default {

data() {

list: [

...

]

},

components: {

TodoInput

},

methods: {

addNewTask(content) {

this.list.push({

id: this.list.length + 1,

task: content,

done: false

});

}

}

}

</script>

实现todo-button组件

  1. 实现代码:
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
<template>

<div class="btn-container mt-3">

<div class="button-group">

<button class="btn btn-primary">全部</button>

<button class="btn btn-secondary">未完成</button>

<button class="btn btn-secondary">已完成</button>

</div>

</div>

</template>

<style>

.btn-container {

width: 400px;

text-align: center;

}

</style>
  1. 点击按钮切换状态,并把状态暴露给App.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
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
<template>

<div class="btn-container mt-3">

<div class="button-group">

<button class="btn" :class="active === index ? 'btn-primary' :
'btn-secondary'" v-for="(item, index) in buttonList"
:key="item.id" @click="buttonClick(index)">{{ item.name
}}</button>

</div>

</div>

</template>

<script>

export default {

data() {

buttonList: [

{

id: 1,

name: "全部"

},

{

id: 2,

name: "未完成"

},

{

id: 3,

name: "已完成"

}

]

},

props: {

active: {

type: Number,

required: true,

default: 0

}

},

methods: {

buttonClick(index) {

if (index === this.active) return;

this.active = index;

this.$emit("update:active", index);

}

}

}

</script>
  1. 在App.vue中存取active变量:
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
<template>

...

<todo-button v-model:active="activeIndex"></todo-button>

...

</template>

<script>

import TodoButton from './components/todo-button.vue';

export default {

data() {

activeIndex: 0

}

}

</script>
  1. 通过计算属性展示对应的列表
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
<template>

...

<todo-list :list="taskList"></todo-list>

...

</template>

<script>

export default {

data() {

activeIndex: 0,

list: []

},

computed: {

taskList() {

switch(this.activeIndex) {

case 0:

return this.list;

case 1:

return this.list.filter(item => !item.done);

case 2:

return this.list.filter(item => item.done);

}

}

}

}

</script>

参考:

Vue3.0-18.案例 -
案例效果及整体实现步骤

Vue3.0-19.案例 -
初始化项目

Vue3.0-20.案例 -
梳理项目结构

Vue3.0-21.案例 - 封装todo-list组件 -
创建并注册TodoList组件

Vue3.0-22.案例 - 封装todo-list组件 -
基于Bootstrap渲染的列表组件

Vue3.0-23.案例 - 封装todo-list组件 -
为TodoList声明props属性

Vue3.0-24.案例 - 封装todo-list组件 -
循环渲染TodoList组件的数据

Vue3.0-25.案例 - 封装todo-list组件 -
使用v-model双向绑定复选框状态

Vue3.0-26.案例 - 封装todo-list组件 -
为已完成的任务添加删除效果

Vue3.0-27.案例 - 封装todo-input组件 -
创建并注册TodoInput组件

Vue3.0-28.案例 - 封装todo-input组件 -
基于Bootstrap渲染组件

Vue3.0-29.案例 - 封装todo-input组件 -
通过自定义事件向外传递数据

Vue3.0-30.案例 - 封装todo-input组件 -
实现添加新任务的功能

Vue3.0-31.案例 - 封装todo-button组件 -
创建并注册TodoButton组件

Vue3.0-32.案例 - 封装todo-button组件 -
渲染TodoButton组件的结构

Vue3.0-33.案例 - 封装todo-button组件 -
通过props指定默认激活按钮

Vue3.0-34.案例 - 封装todo-button组件 -
通过v-model更新激活项的索引

Vue3.0-35.案例 - 封装todo-button组件 -
通过计算属性动态切换列表的数据


本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!