面试题:使用 Vue 开发一个任务列表应用,你会怎么设计实现?

开发一个任务列表应用是 Vue 的经典案例,涵盖了数据管理、组件化、状态管理和用户交互等多个方面。以下是设计和实现的具体步骤:


1. 需求分析

一个任务列表应用通常需要以下功能:

  1. 添加任务:用户可以输入任务内容并添加到列表中。
  2. 标记任务完成:用户可以标记任务为已完成。
  3. 删除任务:用户可以删除任务。
  4. 过滤任务:用户可以查看全部任务、未完成任务或已完成任务。
  5. 持久化存储:任务列表数据在页面刷新后不丢失。

2. 技术选型

  • Vue 3:使用 Composition API 或 Options API。
  • Vuex/Pinia:用于状态管理(可选)。
  • LocalStorage:用于持久化存储任务列表数据。
  • UI 库:如 Element Plus 或 Vant(可选)。

3. 项目结构设计

src/
├── assets/               # 静态资源
├── components/           # 组件
│   ├── TaskList.vue      # 任务列表组件
│   ├── TaskItem.vue      # 任务项组件
│   └── TaskFilter.vue    # 任务过滤组件
├── stores/               # 状态管理
│   └── taskStore.js      # 任务状态管理
├── views/                # 页面
│   └── HomeView.vue      # 主页
├── App.vue               # 根组件
└── main.js               # 入口文件

4. 实现步骤

4.1 创建任务状态管理

使用 Vuex 或 Pinia 管理任务列表的状态。

Vuex 示例
// stores/taskStore.js
import { createStore } from 'vuex';

export default createStore({
  state: {
    tasks: JSON.parse(localStorage.getItem('tasks')) || [],
    filter: 'all', // all, active, completed
  },
  mutations: {
    ADD_TASK(state, task) {
      state.tasks.push(task);
      localStorage.setItem('tasks', JSON.stringify(state.tasks));
    },
    TOGGLE_TASK(state, id) {
      const task = state.tasks.find((task) => task.id === id);
      if (task) task.completed = !task.completed;
      localStorage.setItem('tasks', JSON.stringify(state.tasks));
    },
    DELETE_TASK(state, id) {
      state.tasks = state.tasks.filter((task) => task.id !== id);
      localStorage.setItem('tasks', JSON.stringify(state.tasks));
    },
    SET_FILTER(state, filter) {
      state.filter = filter;
    },
  },
  getters: {
    filteredTasks(state) {
      if (state.filter === 'active') {
        return state.tasks.filter((task) => !task.completed);
      } else if (state.filter === 'completed') {
        return state.tasks.filter((task) => task.completed);
      }
      return state.tasks;
    },
  },
});
Pinia 示例
// stores/taskStore.js
import { defineStore } from 'pinia';

export const useTaskStore = defineStore('task', {
  state: () => ({
    tasks: JSON.parse(localStorage.getItem('tasks')) || [],
    filter: 'all', // all, active, completed
  }),
  actions: {
    addTask(task) {
      this.tasks.push(task);
      localStorage.setItem('tasks', JSON.stringify(this.tasks));
    },
    toggleTask(id) {
      const task = this.tasks.find((task) => task.id === id);
      if (task) task.completed = !task.completed;
      localStorage.setItem('tasks', JSON.stringify(this.tasks));
    },
    deleteTask(id) {
      this.tasks = this.tasks.filter((task) => task.id !== id);
      localStorage.setItem('tasks', JSON.stringify(this.tasks));
    },
    setFilter(filter) {
      this.filter = filter;
    },
  },
  getters: {
    filteredTasks(state) {
      if (state.filter === 'active') {
        return state.tasks.filter((task) => !task.completed);
      } else if (state.filter === 'completed') {
        return state.tasks.filter((task) => task.completed);
      }
      return state.tasks;
    },
  },
});

4.2 创建任务列表组件

<!-- components/TaskList.vue -->
<template>
  <div>
    <input v-model="newTask" @keyup.enter="addTask" placeholder="Add a new task" />
    <ul>
      <TaskItem
        v-for="task in filteredTasks"
        :key="task.id"
        :task="task"
        @toggle="toggleTask"
        @delete="deleteTask"
      />
    </ul>
    <TaskFilter @filter="setFilter" />
  </div>
</template>

<script>
import { computed, ref } from 'vue';
import { useTaskStore } from '../stores/taskStore';
import TaskItem from './TaskItem.vue';
import TaskFilter from './TaskFilter.vue';

export default {
  components: { TaskItem, TaskFilter },
  setup() {
    const taskStore = useTaskStore();
    const newTask = ref('');

    const addTask = () => {
      if (newTask.value.trim()) {
        taskStore.addTask({
          id: Date.now(),
          text: newTask.value.trim(),
          completed: false,
        });
        newTask.value = '';
      }
    };

    return {
      newTask,
      filteredTasks: computed(() => taskStore.filteredTasks),
      addTask,
      toggleTask: taskStore.toggleTask,
      deleteTask: taskStore.deleteTask,
      setFilter: taskStore.setFilter,
    };
  },
};
</script>

4.3 创建任务项组件

<!-- components/TaskItem.vue -->
<template>
  <li :class="{ completed: task.completed }">
    <input type="checkbox" :checked="task.completed" @change="$emit('toggle', task.id)" />
    <span>{{ task.text }}</span>
    <button @click="$emit('delete', task.id)">Delete</button>
  </li>
</template>

<script>
export default {
  props: {
    task: {
      type: Object,
      required: true,
    },
  },
};
</script>

<style scoped>
.completed {
  text-decoration: line-through;
}
</style>

4.4 创建任务过滤组件

<!-- components/TaskFilter.vue -->
<template>
  <div>
    <button @click="$emit('filter', 'all')">All</button>
    <button @click="$emit('filter', 'active')">Active</button>
    <button @click="$emit('filter', 'completed')">Completed</button>
  </div>
</template>

<script>
export default {
  emits: ['filter'],
};
</script>

4.5 在主页中使用任务列表

<!-- views/HomeView.vue -->
<template>
  <div>
    <h1>Task List</h1>
    <TaskList />
  </div>
</template>

<script>
import TaskList from '../components/TaskList.vue';

export default {
  components: { TaskList },
};
</script>

5. 总结

通过以上步骤,可以开发一个功能完整的任务列表应用。关键点包括:

  1. 状态管理:使用 Vuex 或 Pinia 管理任务列表和过滤状态。
  2. 组件化:将任务列表、任务项和过滤功能拆分为独立组件。
  3. 持久化存储:使用 LocalStorage 保存任务列表数据。
  4. 用户交互:实现添加、标记完成、删除和过滤任务的功能。

这种设计模式清晰、可维护性强,适合扩展和优化。

THE END
点赞5 分享
评论 抢沙发
头像
欢迎您留下宝贵的见解!
提交
头像

昵称

取消
昵称表情代码图片

    暂无评论内容