2026-03-20 19:01:14 +08:00

3.2 KiB
Raw Blame History

Home.vue

路径src/views/Home.vue

功能用途

首页,展示分类导航栏(三层级)、事件卡片列表。支持分类筛选、搜索、下拉刷新、触底加载更多。

核心能力

  • 分类导航:三层级分类选择(一级 v-tabs、二级 v-chip、三级 v-tabs
  • 事件列表:卡片式展示,支持下拉刷新、触底加载
  • 搜索:可按关键词搜索事件
  • 分类筛选:选中分类后,自动提取所有层级节点的 tagIds 进行事件筛选;切换语言时重新请求分类接口并刷新列表

UI 细节

  • 卡片阴影不裁剪:列表容器 .home-list-scroll 不使用 overflow-x: hidden,避免卡片两侧阴影被裁剪

  • 分类行分隔.home-category-layer1-row 底部有淡色投影,增强与下方内容的层次感

  • 第一层操作按钮:已移除右侧的搜索/筛选图标;搜索浮层通过 initialSearchExpanded(供 /search 路由使用)控制展开

数据流

PmTagCatalogItem.tagId = [1351]
    ↓ mapCatalogToTreeNode
CategoryTreeNode.tagIds = [1351]
    ↓ 用户选择分类(如:政治 → 特朗普)
activeTagIds = [1351, 1368]  // 合并所有选中层级的 tagIds
    ↓ getPmEventPublic
?tagIds=1351&tagIds=1368

核心计算属性

activeTagIds

收集所有选中层级节点的 tagIds(含父级),用于事件筛选:

const activeTagIds = computed(() => {
  const activeIds = layerActiveValues.value
  const tagIdSet = new Set<number>()

  // 遍历每一层选中的节点,收集所有 tagIds含父级
  let currentNodes = filterVisible(categoryTree.value)
  for (let i = 0; i < activeIds.length; i++) {
    const selectedId = activeIds[i]
    if (!selectedId) continue

    const node = currentNodes.find((n) => n.id === selectedId)
    if (node?.tagIds && node.tagIds.length > 0) {
      node.tagIds.forEach((id) => tagIdSet.add(id))
    }

    currentNodes = filterVisible(node?.children)
  }

  return Array.from(tagIdSet) // 去重后的数组
})

示例

  • 选中「政治」tagIds: [1351])→ activeTagIds = [1351]
  • 选中「政治 → 特朗普」tagIds: [1351] + [1368])→ activeTagIds = [1351, 1368]

使用方式

无需手动调用,路由 / 自动加载。

扩展方式

  1. 新增分类层级:修改 MAX_LAYER 常量,调整模板渲染逻辑
  2. 自定义筛选逻辑:修改 activeTagIds 计算属性
  3. 列表缓存策略:调整 getEventListCache / setEventListCache

二级分类 Chip 样式

  • 未选中variant="outlined"(白底灰边黑字,接近 Vuetify 默认 Chip 外观)
  • 选中variant="tonal" + color="primary"(浅蓝底强调,文字为主题主色)

一级/三级 Tabs 样式Home 页定制)

  • 无下划线:隐藏 Vuetify tabs 的 slider/indicator
  • 选中加粗:选中 tab 使用更粗字重
  • 无点击水波纹:禁用 ripple避免点击涟漪效果
  • 无 hover 效果:禁用鼠标悬停时的背景/遮罩变化
  • 更紧凑:取消 v-tab 默认 min-width 限制,避免强制占宽
  • 第三层更紧凑:三级 tabs 的高度收敛到约 28px接近 2×字体高度