案例介绍
- 使用@vue/cli脚手架搭建vue项目
- 将todos案例组件化开发
TodoHeader.vue组件:todos头部模块TodoMain.vue组件:todos主体模块TodoFooter.vue组件:todos尾部模块
- 运用到的技术点
- Vue组件化开发
- 组件通信
- 计算属性
- watch侦听器
- localStorage本地存储
注意:有更简单的写法,此案例只是为了练习底层写法
效果图
实现代码
1. 根组件
<template>
<div id="app">
<section class="todoapp">
<TodoHeader :todos="list" @addtodo="addtodoFn" @isAllChange="isAllChangeFn"></TodoHeader>
<TodoMain :todos="showTodos" @delTodo="delTodoFn"></TodoMain>
<TodoFooter :todos="list" @statusChange="statusChangeFn" @chearDone="clearDoneFn"></TodoFooter>
</section>
</div>
</template>
<script>
// 1.0 样式引入
import "./styles/base.css";
import "./styles/index.css";
// 2. 引入组件
import TodoHeader from "./components/TodoHeader";
import TodoMain from "./components/TodoMain";
import TodoFooter from "./components/TodoFooter";
export default {
name: "App",
components: {
TodoHeader,
TodoMain,
TodoFooter,
},
data() {
return {
list: JSON.parse(localStorage.getItem('todoList')) || [],
todoStatus: 'all'
}
},
created() {
console.table(this.list);
},
computed: {
// 通过响应书状态 根据待办事项的不同状态切换展示
showTodos() {
if (this.todoStatus === 'done') {
return this.list.filter(item => item.isDone === true);
} else if (this.todoStatus === 'undone') {
return this.list.filter(item => item.isDone === false);
} else {
return this.list;
}
},
},
methods: {
// 添加待办事项
addtodoFn(val) {
console.log('1');
this.list.push({
id: Date.now(),
name: val,
isDone: false
})
console.log(this.list);
},
// 删除待办事项处理函数
delTodoFn(id) {
this.list = this.list.filter(item => item.id !== id);
},
// 切换状态
statusChangeFn(status) {
this.todoStatus = status
},
// 清除已完成事项功能
clearDoneFn() {
console.log('22');
this.list = this.list.filter(item => item.isDone === false);
},
// 根据子组件传递的是否全选状态, 设置待办事项选中状态
isAllChangeFn(val) {
console.log('22');
this.list.forEach(item => item.isDone = val);
}
},
watch: {
list: {
deep: true,
handler() {
localStorage.setItem('todoList', JSON.stringify(this.list))
}
}
}
};
</script>
<style>
</style>
2. 头部组件
<template>
<header class="header">
<h1>todos</h1>
<input id="toggle-all" class="toggle-all" type="checkbox" v-model="isAll" >
<label for="toggle-all"></label>
<input
class="new-todo"
placeholder="输入任务名称-回车确认"
autofocus
@keyup.enter="enterFn"
v-model.trim="inputTodo"
/>
</header>
</template>
<script>
export default {
name: 'TodoHeader',
props: ['todos'],
data() {
return {
inputTodo: '',
}
},
computed: {
isAll: {
get() {
return this.todos.every(item => item.isDone === true);
},
set(val) {
console.log(val);
this.$emit('isAllChange', val)
}
}
},
methods: {
enterFn() {
// 检测输入框不能为空
if (this.inputTodo === '') {
return alert('蠢东西不输入东西怎么给你返回东西')
}
console.log('22');
// 触发父组件自定义事件,通知父组件
this.$emit('addtodo',this.inputTodo);
this.inputTodo = '';
}
}
}
</script>
3. 尾部组件
<template>
<footer class="footer">
<span class="todo-count">剩余<strong>{{ undoneNum }}</strong></span>
<ul class="filters" @click="changeStatus">
<li>
<a @click="todoStatus = 'all'" :class="{selected: todoStatus === 'all'}" href="javascript:;" >全部</a>
</li>
<li>
<a @click="todoStatus = 'undone'" :class="{selected: todoStatus === 'undone'}" href="javascript:;">未完成</a>
</li>
<li>
<a @click="todoStatus = 'done'" :class="{selected: todoStatus === 'done'}" href="javascript:;" >已完成</a>
</li>
</ul>
<button @click="clearDoneBtn" class="clear-completed" >清除已完成</button>
</footer>
</template>
<script>
export default {
name: 'TodoFooter',
props: ['todos'],
data() {
return {
todoStatus: 'all',
}
},
computed: {
undoneNum() {
return this.todos.filter(item => item.isDone === false).length;
}
},
methods: {
// 切换状态过滤待办事项列表, 通知父组件处理
changeStatus(e) {
if (e.target.tagName === 'A') {
console.log(this.todoStatus);
this.$emit('statusChange', this.todoStatus)
}
},
// 清除已完成点击事件, 通知父元素进行数据处理
clearDoneBtn() {
this.$emit('chearDone');
}
}
}
</script>