Skip to content

重构代办事项

因为学过组件了,我们把这个案例改成组件来进行重构。

vue
<template>
  <!-- 最外层的容器 -->
  <section class="todoapp">
    <!-- 头部 -->
    <Header v-model:todos="todos" />
    <!-- 待办列表 -->
    <List v-model:todos="todos" v-model:filteredTodos="filteredTodos" />
    <!-- 底部 -->
    <Footer
      v-model:todos="todos"
      v-model:remaining="remaining"
      @removeAll="removeAllCompleted"
    />
  </section>
</template>

<script setup>
import { ref, computed, watchEffect } from "vue";
import Header from "./components/Header.vue";
import List from "./components/List.vue";
import Footer from "./components/Footer.vue";

// 每一项待办事项的结构如下
// [{id: 1, title: 'xxx', completed: false}]

const STORAGE_KEY = "todo-list";
// 尝试从本地存储中获取数据,如果没有数据则使用空数组(第一次)
const todos = ref(JSON.parse(localStorage.getItem(STORAGE_KEY) || "[]"));
const visibility = ref("all"); // 默认是显示所有待办事项

// 接下来我们需要一个过滤器,用于过滤不同状态的待办事项
const filters = {
  all: (todos) => todos, // 全部
  active: (todos) => todos.filter((todo) => !todo.completed), // 未完成
  completed: (todos) => todos.filter((todo) => todo.completed), // 已完成
};

// 接下来,根据当前的状态(all、active、completed)去调用对应的过滤器函数
const filteredTodos = computed(() => filters[visibility.value](todos.value));
const remaining = computed(() => filters.active(todos.value).length);

// 删除所有已完成
function removeAllCompleted() {
  if (window.confirm("确定要删除所有已完成的待办事项吗?")) {
    todos.value = filters.active(todos.value);
  }
}

// 设置侦听器
watchEffect(() => {
  // 每次 todos 变化时,都需要存储
  // 因为使用到了 todos,因此这个 todos 会变成一个依赖,只要 todos 变化,就会触发这个侦听器
  localStorage.setItem(STORAGE_KEY, JSON.stringify(todos.value));
});

// 监听 hash 变化
window.addEventListener("hashchange", onHashChange);
function onHashChange() {
  const route = window.location.hash.replace(/#\/?/, "");
  if (filters[route]) {
    visibility.value = route;
  } else {
    window.location.hash = "";
    visibility.value = "all";
  }
}
</script>

<style scoped>
@import "./assets/todo.css";
.todoapp {
  background: #fff;
  margin: 130px auto;
  position: relative;
  box-shadow: 0 2px 4px 0 rgba(0, 0, 0, 0.2), 0 25px 50px 0 rgba(0, 0, 0, 0.1);
  width: 800px;
}
</style>

MIT License