TodoList_本地存储

76 阅读2分钟

在TodoList案例(我前边有写到的TodoList案例的实现)上进行改进

删除之前那些写死的数据

image.png image.png

然后我们在输入框输入的事项,可以放在存储这
image.png

通过watch来监视todos,将todos数据放到本地存储上

我们用监视watch来监视todos,不管怎么对todos进行增删改查,只要操作了todos,watch都能监视到,并且把最新的todos存到本地存储里,因为我们只需要new value ,所以不用写old value
image.png

里面的value就是最新的todos,但是如果我们直接把value放进去,它是出不来的
image.png image.png

通过JSON.stringfy()将对象转化为字符串

因为每一个todo项它是一个对象,它不是一个名字,所以我们要通过JSON.stringfy()将对象转化为字符串
image.png image.png

在网页上读取本地存储数据

但是当我们刷新一下页面后,本地存储的数据还在,页面上的事项一刷新就没了
image.png

那是因为我们只是把数据存在本地存储中,我们还没在页面是读取本地存储的数据,所以我们不能将todos写死,要去读取本地存储的数据
image.png

但是我们并不能读取到,因为我们在本地存储里的存的是字符串,我们要的是对象
image.png

通过JSON.parse()来解析得到对象

那么我们就可以用JSON.parse()来解析todos,得到我们想要的对象
image.png image.png

解决清空本地存储后会报错

但是还有一个bug,就是如果我把本地存储给清空,那么我再刷新,它就会报错
image.png image.png

那是因为如果本地存储是空的,那么localStorage.getItem('todos')就会返回null,解析后也是返回null,
image.png

然后App就将为null的todos给footer
image.png

footer就来返回为null的todos的长度,结果就报错了
image.png

我们只要在获取本地存储的数据时,加上一个或空数组就可以了
image.png

再刷新一下就不会报错了
image.png

用watch的深度监视来解决本地存储对done的更新

但是这样还没完成,因为当我给“学习”和“上课”打上已完成,
image.png

刷新之后我的打勾就不见了
image.png

那是因为监视的不是深度监视(不知道的可以看看我写的《09-监视属性》),监视的是第一层,里面的没有监视到,
image.png

那么在watch里写的就不能是简写形式,要写完整版形式(不知道的可以看看我写的《09-监视属性》)
image.png

这样你在事项上打勾,本地存储里对应事项的done也会变成true
image.png

本结的主要代码如下:

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>