Skip to content

5.4 开发首页页面

首页是本项目的主要操作页面,该页面包含文件夹列表、备忘录列表和备忘录编辑等功能。

因为首页的内容比较多,所以将文件夹列表和备忘录列表单独提取为组件,页面中只保留编辑器的部分。

5.4.1 编写首页组件

首页组件就是根组件 Home.vue,接下来我们编写这个组件。

(1)编辑模版代码,结构如下:

vue
<!-- Home.vue -->
<template>
  <main class="home-point">
    <cus-header></cus-header>
    <router-view></router-view>
  </main>
</template>
<script setup lang="ts">
import CusHeader from "@/components/CusHeader.vue";
</script>

上面代码的模板中只用了两个组件:公共头部组件和路由视图组件。

  • 公共头部组件:只会加载一次,对除登录页外的所有页面生效。
  • 路由视图组件:用于匹配定义在首页组件下动态切换的所有子路由组件。

(2)新建 views/index/index.vue 文件表示首页组件,并为该组件配置路由:

js
// router/index.ts
routes: [
  {
    path: "/",
    component: HomeView,
    redirect: "/index",
    children: [
      {
        path: "index",
        component: () => import("@/views/index/index.vue"),
      },
    ],
  },
];

在上面的代码中,首页被配置为首页根组件 Home.vue 的二级路由,同时添加了“redirect: '/index'”配置来保证打开网址时自动重定向到首页。

(3)按照左、中、右三栏布局结构编写模板代码:

vue
<template>
  <div class="index-page">
    <div class="catalogs">
      <!--文件夹区域-->
      <Cataloge></Cataloge>
    </div>
    <div class="memos">
      <!--备忘录列表区域-->
      <Menos></Menos>
    </div>
    <div class="detail">
      <!--编辑器区域-->
    </div>
  </div>
</template>

上述代码使用了 Cataloge 组件和 Menos 组件,即单独提取的文件夹列表组件和备忘录列表组件。编辑器区域的内容会在下一节展开介绍。

(4)编写 JavaScript 代码引入 Cataloge 组件和 Menos 组件,并初始化首页 Store:

vue
<script setup lang="ts">
import { indexStore } from "@/stores";
import Cataloge from "./catalogs.vue";
import Menos from "./menos.vue";
const store = indexStore();
</script>

上述代码在同级目录下导入两个子组件,5.3.5 节和 5.3.6 节会详细介绍这两个组件。

(5)使用 Flex 布局实现页面结构的排版:

vue
<style lang="less">
.index-page {
  display: flex;
  align-items: stretch;
  height: calc(100vh - 55px);
  .catalogs {
    width: 20%;
    background: #f9f9f9;
  }
  .memos {
    width: 25%;
  }
  .detail {
    flex: 1;
  }
}
</style>

至此,完成首页的基本结构。

5.4.2 编写首页 Store

在首页中引入首页 Store,该 Store 会存储很多状态用于在首页和其子组件中使用。下面编写首页 Store 的代码。

(1)新建 stores/index 文件夹,并添加 index.ts 文件和 type.ts 文件。在 index.ts 文件中创建首页 Store:

js
import { defineStore } from "pinia";
const indexStore = defineStore("index", {
  state: () => ({}),
});
export default indexStore;

(2)在 type.ts 文件中定义文件夹和备忘录的类型:

js
export interface CatalogType {
  cata_id: number; // 文件夹 ID
  user_id: number; // 用户 ID
  cata_name: string; // 文件夹名称
}
export interface MemoType {
  memo_id: number; // 备忘录 ID
  cata_id: number; // 文件夹 ID
  title: string; // 备忘录标题
  content: string; // 备忘录内容
  update_at: number; // 更新时间
}

在上述代码中,CatalogType 表示文件夹类型,MemoType 表示备忘录类型。文件夹数据和备忘录数据的字段必须严格匹配类型文件中的定义。

(3)在首页 Store 中添加 4 个状态,分别是文件夹列表、备忘录列表、当前文件夹 ID 和当前备忘录 ID。各状态的定义如下:

js
state: () => ({
  catalogs: [] as CatalogType[], // 文件夹列表
  memos: [] as MemoType[], // 备忘录列表
  active_cataid: null as number | null, // 当前文件夹 ID
  active_memoid: null as number | null, // 当前备忘录 ID
}),

在首页和子组件中读取这些状态,可以渲染出文件夹和备忘录的数据。

(4)添加设置状态的方法。从 localStorage 中获取数据并为 catalogs 状态和 memos 状态赋值,同时添加设置 active_cataid 和 active_memoid 的方法,编写 Action:

js
actions: {
  // 获取目录列表
  getCatalogs() {
    let data = localGetItem("catalogs");
    if (data) {
      this.catalogs = data;
    }
  },
  // 获取备忘录列表
  getMemos() {
    let data = localGetItem("memos");
    if (data) {
      this.memos = data;
    }
  },
  // 设置备忘录 ID
  setMemoId(id: number | null) {
    this.active_memoid = id;
    localSetItem("active_memoid", id);
  },
  setCateId(id: number | null) {
    this.active_cataid = id;
    localSetItem("active_cataid", id);
  }
}

(5)在 stores/index.ts 文件中将首页 Store 全局导出:

js
export { default as indexStore } from "./index/index";

至此,可以在首页组件中导入并使用这些在首页 Store 中定义的状态和方法。