在TodoList案例(我前边有写到的TodoList案例的实现)上进行改进
删除之前那些写死的数据
然后我们在输入框输入的事项,可以放在存储这
通过watch来监视todos,将todos数据放到本地存储上
我们用监视watch来监视todos,不管怎么对todos进行增删改查,只要操作了todos,watch都能监视到,并且把最新的todos存到本地存储里,因为我们只需要new value ,所以不用写old value
里面的value就是最新的todos,但是如果我们直接把value放进去,它是出不来的
通过JSON.stringfy()将对象转化为字符串
因为每一个todo项它是一个对象,它不是一个名字,所以我们要通过JSON.stringfy()将对象转化为字符串
在网页上读取本地存储数据
但是当我们刷新一下页面后,本地存储的数据还在,页面上的事项一刷新就没了
那是因为我们只是把数据存在本地存储中,我们还没在页面是读取本地存储的数据,所以我们不能将todos写死,要去读取本地存储的数据
但是我们并不能读取到,因为我们在本地存储里的存的是字符串,我们要的是对象
通过JSON.parse()来解析得到对象
那么我们就可以用JSON.parse()来解析todos,得到我们想要的对象
解决清空本地存储后会报错
但是还有一个bug,就是如果我把本地存储给清空,那么我再刷新,它就会报错
那是因为如果本地存储是空的,那么localStorage.getItem('todos')就会返回null,解析后也是返回null,
然后App就将为null的todos给footer
footer就来返回为null的todos的长度,结果就报错了
我们只要在获取本地存储的数据时,加上一个或空数组就可以了
再刷新一下就不会报错了
用watch的深度监视来解决本地存储对done的更新
但是这样还没完成,因为当我给“学习”和“上课”打上已完成,
刷新之后我的打勾就不见了
那是因为监视的不是深度监视(不知道的可以看看我写的《09-监视属性》),监视的是第一层,里面的没有监视到,
那么在watch里写的就不能是简写形式,要写完整版形式(不知道的可以看看我写的《09-监视属性》)
这样你在事项上打勾,本地存储里对应事项的done也会变成true
本结的主要代码如下:
App.vue
<template>
<div id="root">
<div class="todo-container">
<div class="todo-wrap">
<UserHeader :AddTodoObj="AddTodoObj" />
<UserList
:todos="todos"
:checkTodo="checkTodo"
:deleteTodo="deleteTodo"
/>
<UserFooter
:todos="todos"
:checkAllTodo="checkAllTodo"
:clearAllTodo="clearAllTodo"
/>
</div>
</div>
</div>
</template>
<script>
// 引入组件
import UserHeader from "./components/UserHeader.vue";
import UserList from "./components/UserList.vue";
import UserFooter from "./components/UserFooter.vue";
export default {
name: "App",
components: { UserHeader, UserList, UserFooter },
data() {
return {
todos:
// { id: "001", title: "打代码", done: true },
// { id: "002", title: "看电视剧", done: true },
// { id: "003", title: "洗碗", done: false },
JSON.parse(localStorage.getItem("todos")) || [],
};
},
methods: {
// 添加一个todo
AddTodoObj(todoObj) {
this.todos.unshift(todoObj);
// console.log("我是App组件,我收到了数据", x);
},
// 勾选or取消勾选一个todo
checkTodo(id) {
this.todos.forEach((todo) => {
if (todo.id === id) todo.done = !todo.done;
});
},
// 删除一个todo
deleteTodo(id) {
this.todos = this.todos.filter((todo) => todo.id !== id);
},
//全选or取消全选
checkAllTodo(done) {
this.todos.forEach((todo) => {
todo.done = done;
});
},
// 清除所有已完成
clearAllTodo() {
this.todos = this.todos.filter((todo) => {
// return todo.done == false;
return !todo.done;
});
},
},
watch: {
todos: {
deep: true,
handler(value) {
localStorage.setItem("todos", JSON.stringify(value));
},
},
},
};
</script>
<style>
/* base */
body {
background-color: #fff;
/* margin: 0; */
}
.todo-container {
width: 600px;
margin: 0 auto;
/* background-color: antiquewhite; */
}
.todo-container .todo-wrap {
padding: 10px;
border: 1px solid #ddd;
border-radius: 5px;
}
.btn {
display: inline-block;
padding: 4px 12px;
/* margin-bottom: 0; */
font-size: 14px;
/* line-height: 20px; */
/* text-align: center; */
/* vertical-align 用来指定行内元素(inline)或表格单元格(table-cell)元素的垂直对齐方式 */
vertical-align: middle;
cursor: pointer;
box-shadow: inset 0 1px 0px rgba(255, 255, 255, 0.2),
0 1px 2px rgba(0, 0, 0, 0.05);
border-radius: 4px;
}
.btn:focus {
/* outline: none; */
}
.btn-danger {
color: #fff;
background-color: #da4f49;
border: 1px solid #bd362f;
}
.btn-danger:hover {
color: #fff;
background-color: #bd362f;
}
</style>