todoList组件化编码流程
所需依赖项:nanoid 生成唯一id,使用npm下载
1.拆分页面结构
├─todoList --------------------------------- // 页面文件夹
│ ├─components ---------------------- // 组件文件夹
│ ├ ├─j-head --------------------- // 头部
│ ├ ├─j-list ----------------------- // 列表
│ ├ ├─j-item --------------------- // 子项
│ ├ ├─j-footer ------------------- // 底部
│ ├─index.vue ------------------------ // 父组件页面
2.页面代码
index.vue
<template>
<div>
<div class="todo-list-box">
<j-head @addTodo="addTodo"></j-head>
<j-list :todoList="todoList" @delTodo="delTodo" @selectTodo="selectTodo"></j-list>
<j-footer :todoList="todoList" @delComplete="delComplete" @isAllCheck="isAllCheck"></j-footer>
</div>
</div>
</template>
<script>
import jHead from './j-head';
import jList from './j-list';
import jFooter from './j-footer';
import { nanoid } from 'nanoid';
export default {
components: { jHead, jList, jFooter },
data() {
return {
todoList: [
{
id: nanoid(),
title: '睡觉',
select: true
},
{
id: nanoid(),
title: '吃饭',
select: false
},
{
id: nanoid(),
title: '学习',
select: false
}
]
};
},
methods: {
/** 添加事件 */
addTodo(obj) {
this.todoList.unshift(obj);
},
/** 删除事件 */
delTodo(id) {
if (!confirm('确定删除吗?')) return;
this.todoList = this.todoList.filter((item) => item.id != id);
},
/** 勾选事件 */
selectTodo(obj) {
this.todoList.filter((item) => item.id === obj.id)[0].select = !obj.select;
},
/** 删除已完成事件 */
delComplete() {
this.todoList = this.todoList.filter((item) => !item.select);
},
/** 是否全选 */
isAllCheck(is) {
this.todoList.forEach((item) => (item.select = is));
}
}
};
</script>
<style lang="less" scoped>
.todo-list-box {
width: 95vw;
padding: 10px;
margin: 15px auto;
border: 1px solid #eee;
border-radius: 5px;
}
</style>
j-head.vue
<template>
<div class="j-head-box">
<input type="text" @keyup.enter="add" />
</div>
</template>
<script>
import { nanoid } from 'nanoid';
export default {
methods: {
/** 添加待办事项 */
add(e) {
if (!e.target.value.trim()) return alert('请输入事件名');
const todoObj = { id: nanoid(), title: e.target.value, select: false };
this.$emit('addTodo', todoObj);
e.target.value = '';
}
}
};
</script>
<style lang="less" scoped>
.j-head-box {
width: 100%;
height: 30px;
input {
width: 100%;
height: 100%;
border-radius: 5px;
border: 1px solid #eee;
}
}
</style>
j-list.vue
<template>
<div class="j-list-box">
<template v-for="item in todoList">
<j-item :key="item.id" :item="item" v-on="$listeners"></j-item>
</template>
</div>
</template>
<script>
import jItem from './j-item.vue';
export default {
components: { jItem },
props: {
todoList: Array
}
};
</script>
<style lnag="less" scoped>
.j-list-box {
border: 1px solid #eee;
margin: 10px 0;
border-radius: 3px;
border-top: none;
}
</style>
j-item.vue
<template>
<div class="j-item-box">
<label>
<input type="checkbox" :checked="item.select" @change="selectTodo(item)" />
<span>{{ item.title }}</span>
</label>
<button @click="delTodo(item.id)">删除</button>
</div>
</template>
<script>
export default {
props: {
item: Object
},
methods: {
/** 勾选事件 */
selectTodo(item) {
this.$emit('selectTodo', item);
},
/** 删除事件 */
delTodo(id) {
this.$emit('delTodo', id);
}
}
};
</script>
<style lang="less" scoped>
.j-item-box {
display: flex;
align-items: center;
font-size: 14px;
padding: 10px 5px;
border-top: 1px solid #eee;
label {
flex: 1;
display: flex;
align-items: center;
}
span {
flex: 1;
margin-left: 5px;
}
button {
color: white;
font-size: 12px;
margin-left: auto;
background-color: red;
border: none;
border-radius: 3px;
padding: 0 4px;
}
}
</style>
j-footer.vue
<template>
<div class="j-footer-box">
<input type="checkbox" v-model="isAll" />
<span>已完成{{ completeCount }}/全部{{ todoList.length }}</span>
<button @click="delComplete">清除全部已完成任务</button>
</div>
</template>
<script>
export default {
props: {
todoList: Array
},
computed: {
/** 计算已完成事件个数 */
completeCount() {
return this.todoList.reduce((pre, item) => (item.select ? pre + 1 : pre), 0);
},
/** 是否全选 */
isAll: {
get() {
return this.todoList.length === this.completeCount && this.todoList.length > 0;
},
set(value) {
this.$emit('isAllCheck', value);
}
}
},
methods: {
/** 清除已完成事项 */
delComplete() {
this.$emit('delComplete');
}
}
};
</script>
<style lang="less" scoped>
.j-footer-box {
display: flex;
justify-content: space-between;
align-items: center;
padding: 0 5px;
span {
flex: 1;
margin-left: 30px;
}
button {
padding: 2px 5px;
border: none;
color: #fff;
border-radius: 3px;
background-color: red;
}
}
</style>
3.涉及知识点
computed:vue中计算计算函数
var vm = new Vue({
data: { a: 1, b: 1 },
computed: {
/**
* 仅读取
* 一般使用此方法
* */
sumB() {
return this.b + 7;
},
/**
* 读取和设置
* 特殊情况使用例:v-model使用计算函数绑定时
* */
sumA: {
/** 读取 */
get() {
return this.a + 1;
},
/** 设置 */
set(v) {
this.a = v - 1;
},
},
},
});
vm.sumB; // sumB = 8
vm.Suma; // 调用get方法结果为 Suma = 2
vm.sumA = 3; // 调用set方法 v = 3, a = 2, sumA = 3
this.$emit(@event,$event):绑定一个自定义事件,当这行代码执行时将参数传给父组件。
参数说明
参数名 | 说明 | 类型 |
@evnet | 父组件接收的方法名 | String |
$event | 父组件接收的参数 | / |
$listeners:是一个对象,内容为组件上的所有监听器