Skip to content

分类

作者:Yuan Tang
更新于:5 个月前
字数统计:1.6k 字
阅读时长:5 分钟

一级分类

一级分类设置

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

  1. 路由文件添加对应路由,这里采取把 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')
            },
          ]
        },
      ],
    })
  2. 页面中通过 RouterLink 组件的 to 属性定义要跳转的路径,改为对应 id 即可

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

面包屑

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

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

分类Banner

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

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

    js
    export function getBannerAPI(params = {}) {
      const { distributionSite = '1' } = params
      return http({
        url: '/home/banner',
        params: {
          distributionSite
        }
      })
    }
  2. 封装轮播图组件以复用

    vue
    <script setup>
    defineProps({
      bannerList: {
        type: Array,
        required: true
      },
      height: {
        type: [String, Number],
        default: 500
      }
    })
    
    /*
    * 点击轮播图
    * e:当前被点击的轮播图的数据
    */
    function 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>
  3. 分类组件中引入使用(首页轮播图也可使用复用的组件),然后单独对应参数获取对应数据即可

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

  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 { onBeforeRouteUpdate, useRoute } 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 GoodsItem from '../Home/components/GoodsItem.vue'
    import { useBanner } from './composables/useBanner'
    import { useCategory } from './composables/useCategory'
    import BannerCarousel from '@/components/BannerCarousel.vue'
    
    const { bannerList } = useBanner()
    const { categoryData } = useCategory()
    </script>

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

二级分类

创建

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

  1. 设置静态模块

  2. 创建路由

    js
    {
      path: 'category/sub/:id',
      component: () => import('@/views/SubCategory/index.vue')
    },
  3. 在对应的 RouterLink 标签的 to 属性中设置对应的跳转路径

    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
    }
  }
})

Contributors

Yuan Tang