跳转到内容

分类

刀刀

1/2/2025

0 字

0 分钟

一级分类

一级分类设置

点击顶部导航栏跳转到对应的一级分类页面,按照如下步骤:

  1. 路由文件添加对应路由,这里采取把 id 添加到路由上,为必传项,因此需要 : 占位表示此数据为动态数据

  2. 页面中通过 RouterLink 组件的 to 属性定义要跳转的路径,改为对应 id 即可

js
const router = createRouter({
  history: createWebHistory(import.meta.env.BASE_URL),
  // path和component对应关系的位置
  routes: [
    {
      path: '/',
      component: Layout,
      children: [
        // ...
        {
          path: 'category/:id',
          component: () => import('@/views/Category/index.vue')
        },
      ]
    },
  ],
})
vue
<RouterLink :to="`category/${item.id}`">{{ item.name }}</RouterLink>

面包屑

面包屑导航主要步骤如下:

  1. 复制粘贴静态面包屑模板
  2. 封装接口函数
  3. 在面包屑 .vue 组件中引入接口函数,获取路由上的 id 作为参数传参
  4. 获取接口数据动态渲染

分类Banner

分类处轮播图主要步骤如下:

  1. 修改封装的轮播图接口,用于接收不同的参数(首页轮播图不用传,可使用默认值)

  2. 封装轮播图组件以复用

  3. 分类组件中引入使用(首页轮播图也可使用复用的组件),然后单独对应参数获取对应数据即可

js
export const getBannerAPI = (params = {}) => {
  const { distributionSite = '1' } = params
  return http({
    url: '/home/banner',
    params: {
      distributionSite
    }
  })
}
vue
<script setup>
defineProps({
  bannerList: {
    type: Array,
    required: true
  },
  height: {
    type: [String, Number],
    default: 500
  }
})

/*
* 点击轮播图
* e:当前被点击的轮播图的数据
*/
const handleCarouselFn = e => {
  // this.$router.push(e.hrefUrl)
}
</script>

<template>
  <el-carousel :height="height + 'px'">
      <el-carousel-item v-for="item in bannerList" :key="item.id" @click="handleCarouselFn(item)">
        <img :src="item.imgUrl" alt="">
      </el-carousel-item>
    </el-carousel>
</template>

<style scoped>

</style>

导航激活设置分类列表渲染

  1. 导航激活

    点击对应导航却没有相应的激活样式,不利于用户体验。而组件 RouterLink 有一个属性 active-class ,当其 to 属性的值与路由的值匹配,则会处于激活状态,获取等号后的激活样式。

    vue
    <RouterLink active-class="active" :to="`/category/${item.id}`">{{ item.name }}</RouterLink>

    现在为 active 做对应的样式设置即可。

  2. 分类渲染

    渲染对应内容即可。

路由缓存

Vue 官方文档有一段说明:使用带参数的路由时,当用户从 /category/01 跳转到 /category/02 时,相同的组件实例将会被重复使用,减少性能消耗。但是这也意味着生命周期钩子不会被调用。

解决思路:

  1. 让组件实例不再复用,强制销毁重建
  2. 监听路由变化,变化后执行数据更新操作

方案一

Vue 中,:key 不仅可以用来配合 v-for 使用,同时也能作用于强制替换一个元素、组件而不是复用它。

在二级路由处添加 :key 属性,值为当前完整路由,代码如下:

vue
<router-view :key="$route.fullPath"></router-view>

刷新后查看页面,发现效果实现了,但是有一个问题,我们只需要内容区域接口重新获取,而它把不需要重新调用的轮播图接口也重复请求。如果接口多的话,这样很影响性能。

方案二

Vue 路由提供了一个方法 onBeforeRouteUpdate ,在路由参数发生变化时触发。其中有一个 to 参数,接收最新的路由参数。因此获取最新的路由参数的 id ,单纯调用分类接口,这样不至于消耗太大的性能。

js
import { onBeforeRouteUpdate } from "vue-router";

/**
 * 侦听路由变化,重新调用接口
 * to:当前最新路由参数
 * */
onBeforeRouteUpdate((to) => {
  // 存在问题:使用最新的路由参数请求最新的分类数据
  getTopCategoryFn(to.params.id);
})

逻辑函数拆分业务

分类模块根据业务逻辑拆分,每个 js 模块负责自己的逻辑。返回需要的变量和方法后组件内部调用使用即可。

  • 轮播图

  • 分类

  • 组件

js
import { onMounted, ref } from "vue";
import { getBannerAPI } from "@api/layout";

export function useBanner() {
  const bannerList = ref([]); // 轮播图数组

  const getBannerFn = async () => {
    const res = await getBannerAPI({
      distributionSite: "2",
    });
    bannerList.value = res.result;
  };

  onMounted(() => {
    getBannerFn();
  });

  return {
    bannerList
  }
}
js
import { onMounted, ref } from "vue";
import { getTopCategoryAPI } from "@api/category";
import { useRoute, onBeforeRouteUpdate } from "vue-router";

export function useCategory() {
  const categoryData = ref({}); // 分类数据
  const route = useRoute(); // 路由对象

  const getTopCategoryFn = async (id) => {
    const res = await getTopCategoryAPI(id);
    categoryData.value = res.result;
  };

  onMounted(() => getTopCategoryFn(route.params.id));

  /**
 * 侦听路由变化,重新调用接口
 * to:当前最新路由参数
 * */
  onBeforeRouteUpdate((to) => {
    // 存在问题:使用最新的路由参数请求最新的分类数据
    getTopCategoryFn(to.params.id);
  })

  return {
    categoryData,
  }
}
vue
<script setup>
// 轮播图组件
import BannerCarousel from "@/components/BannerCarousel.vue";
import GoodsItem from "../Home/components/GoodsItem.vue";
import { useBanner } from './composables/useBanner'
import { useCategory } from './composables/useCategory'

const { bannerList } = useBanner()
const { categoryData } = useCategory()
</script>

这样后续无论是维护还是新增功能都很方便。

二级分类

创建

二级分类创建主要步骤如下:

  1. 设置静态模块

  2. 创建路由

  3. 在对应的 RouterLink 标签的 to 属性中设置对应的跳转路径

js
{
  path: 'category/sub/:id',
  component: () => import('@/views/SubCategory/index.vue')
}
vue
<RouterLink :to="`/category/sub/${i.id}`">

面包屑

  1. 封装接口获取面包屑数据

  2. 动态设置面包屑名称,通过返回的面包屑的父亲 id 拼接的方式设置跳转路径

    vue
    <el-breadcrumb separator=">">
      <el-breadcrumb-item :to="{ path: '/' }">首页</el-breadcrumb-item>
      <el-breadcrumb-item
        :to="{ path: `/category/${subCategoryData.parentId}` }"
        >{{ subCategoryData.parentName }}
      </el-breadcrumb-item>
      <el-breadcrumb-item>{{ subCategoryData.name }}</el-breadcrumb-item>
    </el-breadcrumb>

分类模块

  1. 首先封装接口函数,调用接口获取数据,引入之前封装好的商品模块组件即可

  2. 列表筛选模块主要是根据传参的不同实现

  3. 列表无限滚动则是根据 elementPlus 提供的 v-infinite-scroll 指令判断触底,满足条件后页码自增1,获取新数据后做新老数据拼接渲染

    基础用法

    在要实现滚动加载的列表上上添加v-infinite-scroll,并赋值相应的加载方法,可实现滚动到底部时自动执行加载方法。

    禁用只需添加 :infinite-scroll-disabled="disabled"disabled 为真即可。

路由滚动行为设置

切换二级分类后想要页码返回顶部,可以使用 vue-router 提供的 scrollBehavior 方法,方法使用如下:

js
const router = createRouter({
  history: createWebHistory(import.meta.env.BASE_URL),
  // path和component对应关系的位置
  routes: [
    // ...
  ],
  // 路由滚动行为定制
  scrollBehavior (to, from, savedPosition) {
    return {
      top: 0
    }
  }
})