vue3入门16 - 组件化 todoMvc 项目-业务封装1

108 阅读2分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第23天,点击查看活动详情

前言

  • 这一节,我们要对业务逻辑进行下封装。
  • 所谓业务封装,指的自然是和业务相关的内容,比如我们todos数据的增删改查就属于业务逻辑,这些逻辑只能在这个项目中使用,类似于todo项目的业务可能有复用的机会。
  • 封装之后业务逻辑会更加清晰,维护起来也更方便。

todos 数据处理封装

  • 我们先对todos数据的各种计算、过滤显示进行封装

todos数据本地存储

  • 我们使用hook函数来进行封装,当数据变化时存储到本地,最终返回todos数据
// useTodosStore.js
import { ref } from 'vue';
import { storage } from '@/utils/storage';

export const useTodosStore = () => {
  const KEY = 'latest_todos';
  const todos = ref(storage.get(KEY) || []);
  watchEffect(() => {
    storage.set(KEY, todos.value);
  });
  return {
    todos
  };
};

  • 在页面上进行调用时,把这个函数调用注入到provide中,方便后面我们在其他组件使用此数据
// App.vue
const todosStore = useTodosStore();
const { todos, remaining } = todosStore;
provide('todosStore', todosStore);
  • 修改Header.vue组件的todos数据操作
const { todos } = inject('todosStore');
const input = ref('');
const addTodo = () => {
  const text = input.value;
  if (!text) return;
  todos.value.push({ id: todos.value.length + 1, text, completed: false });
  input.value = '';
};

对比下代码,相比于之前使用props传递数据的通信方式,使用依赖注入代码要更简洁、更清晰。 image.png 下面我们把所有用到todos数据的地方都做下重构,这里就不一一写了。

其他逻辑封装

接着我们把跟todos数据处理相关的一些业务也都封装到useTodoStore中。

import { ref, watchEffect, computed } from 'vue';
import { storage } from '@/utils/storage';
import { useEventListener } from '@/hooks/useEventListener';

export const filters = {
  all: (todos) => todos,
  active: (todos) => todos.filter((todo) => !todo.completed),
  completed: (todos) => todos.filter((todo) => todo.completed)
};

export const useTodosStore = () => {
  const KEY = 'latest_todos';
  const todos = ref(storage.get(KEY) || []);
  watchEffect(() => {
    storage.set(KEY, todos.value);
  });
  // 显示类型
  const visibility = ref('all');
  // 根据类型显示对应的todos数据
  const filteredTodos = computed(() => filters[visibility.value](todos.value));
  // 进行中的数量
  const remaining = computed(() => filters.active(todos.value).length);
  // 完成所有todo操作
  const allDone = computed({
    get: () => !remaining.value,
    set: (value) => {
      todos.value.forEach((todo) => {
        todo.completed = value;
      });
    }
  });
  // 监听浏览器hash变化
  const onHashChange = () => {
    const hash = window.location.hash.replace(/#\/?/, '');
    if (filters[hash]) {
      visibility.value = hash;
    } else {
      visibility.value = 'all';
      window.location.hash = '';
    }
  };
  useEventListener('hashchange', onHashChange);
  return {
    todos,
    filteredTodos,
    remaining,
    visibility,
    allDone
  };
};
  • 当我们把所有和todos数据处理相关逻辑都重构完,你会发现App.vue瞬间更加清爽了。

image.png 没有了props的束缚,所有数据通过依赖注入完成响应式更新,哪里需要用数据就在哪个组件里调用,方便的很,也更好维护了。

总结

相比于props进行数据的通信,使用依赖注入的方式,使得整个项目数据逻辑要更加简洁,整体逻辑更加好维护。

项目代码在GitHub,可以查阅。