首先,我们需要理清楚什么是一级分类,上一篇文章中,我们已经请求后台接口拿到了导航栏中不同商品分类相关的数据,那么,我们怎样编写代码来实现这样一个效果呢?当我们点击不同分类的时候,首页会渲染出该分类下的所有商品?在这里,就需要我们配置一级分类的路由,当我们点击每个分类的时候,拿到这个分类对应的id,然后携带着去向后台发起数据请求,然后在底下渲染出来。
详细步骤如下:
(1)配置占位符
{
          path: 'category/:id',
          component: Category
        },(2)点击跳转
 <RouterLink active-class="active" :to="`/category/${item.id}`">
        {{ item.name }}
      </RouterLink>2、一级分类-面包屑导航渲染
先来看下效果:在导航栏中,当我们点击某个商品分类的时候,例如,在这里点了“居家”

在底下会弹出这样一个效果,可以让用户看着更加舒服,

其实这个呢,就是面包屑,接下来,一起看看怎么实现吧?
首先,我们需要知道这个数据来自哪里?很显然是后端接口传过来的数据。那么,首先,我们就需要封装接口,去向后台请求这个数据。
(1)封装接口
export function getCategoryAPI (id) {
  return request({
    url: '/category',
    params: {
      id
    }
  })
}(2)调用接口返回数据:
<script setup>
import { getCategoryAPI } from '@/apis/category'
import { tryOnMounted } from '@vueuse/core';
import { ref } from 'vue'
import {useRoute } from 'vue-router'
const route = useRoute()
const categoryData = ref([])
const getCategory = async () => {
  const res = await getCategoryAPI(route.params.id)
  categoryData.value = res.result
  console.log(res)
}
tryOnMounted(()=>getCategory())
</script>
浏览器返回:


(3)模板渲染

3、一级分类-轮播图功能实现
通过观察整个项目,我们发现,一级分类下的轮播图和首页的轮播图结构是一模一样的,只是调用的接口不同,在这里,很显然,我们可以把之前首页的轮播图相关的逻辑代码直接拿过来复用,只需要修改一下参数即可。
(1)改造接口(apis/home.js)
export function getBannerAPI (params = {}) {
  // 轮播图数据,1为首页, 2为商品分类页,默认为1
  const { distributionSite = '1' } = params
  return httpInstance({
    url: '/home/banner',
    params: {
      distributionSite
    }
  })
}
(2)HomeBanner中获取数据
<script setup>
import { getBannerAPI } from '@/apis/home'
import { onMounted, ref } from 'vue'
const bannerList = ref([])
const getBanner = async () => {
  const res = await getBannerAPI()
  console.log(res)
  bannerList.value = res.result
}
onMounted(() => getBanner())
</script>
查看接口是否发送成功:这里的接口是1

根据后台数据要求,更改参数设置,“2”为商品分类页

修改代码,这里的接口变成了2

把首页轮播图的相关代码拿过来:
<template>
  <div class="home-banner">
    <el-carousel height="500px">
      <el-carousel-item v-for="item in bannerList" :key="item.id">
        <img :src="item.imgUrl" alt="">
      </el-carousel-item>
    </el-carousel>
  </div>
</template>
样式代码也拿过来:
<style scoped lang='scss'>
.home-banner {
  width: 1240px;
  height: 500px;
  position: absolute;
  left: 0;
  top: 0;
  z-index: 98;
  img {
    width: 100%;
    height: 500px;
  }
}
</style>保存之后,查看运行结果:

4、一级分类-激活状态控制和分类列表渲染
(1)激活状态显示:
直接添加类名即可
active-class="active"(2)分类列表渲染
1)Category/index.vue中轮播图下面添加如下静态代码:
<div class="sub-list">
        <h3>全部分类</h3>
        <ul>
          <li v-for="i in categoryData.children" :key="i.id">
            <RouterLink :to="`/category/sub/${i.id}`">
              <img :src="i.picture" />
              <p>{{ i.name }}</p>
            </RouterLink>
          </li>
        </ul>
      </div>
      <div class="ref-goods" v-for="item in categoryData.children" :key="item.id">
        <div class="head">
          <h3>- {{ item.name }}-</h3>
        </div>
        <div class="body">
          <GoodsItem v-for="good in item.goods" :goods="good" :key="good.id" />
        </div>
      </div>2)V-for遍历已有数据
 <div class="ref-goods" v-for="item in categoryData.children" :key="item.id">
        <div class="head">
          <h3>- {{ item.name }}-</h3>
        </div>
        <div class="body">
          <GoodsItem v-for="good in item.goods" :goods="good" :key="good.id" />
        </div>
      </div>3)由于这里每个商品分类下的模块使用到了GoodsItem中的模板,所以需要将其引入。
import GoodsItem from '../Home/components/GoodsItem.vue'5、一级分类-路由缓存问题解决
首先,来看看什么是路由缓存问题?为什么会出现这个问题?
由于路由在只有参数变化时,会复用组件实例,会导致生命周期函数不执行,这个问题体现在哪里呢?当我们从导航栏中的某一个商品分类切换到下一个分类的时候,我们可以看到这样一个问题:浏览器地址栏的数据确实在发生变化,导航栏中的下一个商品分类也确实被激活了,但是分类下的数据根本就没有发生变化,这样,很显然是不行的,那么,我们怎样去解决这个问题呢?既然是组件实例被复用了,那么,我们就寻思让组件实例不再复用。很显然,这种方法是可行的,来看一下实现过程。
 <!-- 添加key,破坏复用机制,强制销毁重建 -->
  
  <RouterView :key="$route.fullPath"/>
但是,这种方法虽然简单粗暴,设置之后,组件实例确实不复用了,但是,它也存在一个很严重的问题。
它把整个实例都销毁重建了。在浏览器我们看到这个效果(看最上面两行)

每次点击都会请求这两个接口
而在项目中,每个分类下面的轮播图是一样的,不需要重新请求数据,所以,这种方法仍然存在资源的浪费,那么,还有没有其它的办法呢?肯定是有的,只要思想不滑坡,办法总比困难多。beforeRouteUpdate这个导航钩子它提供了一种解决方案,它可以用来监听路由参数的变化,当路由参数发生变化时,重新向后台发送接口请求。
详细步骤如下:
(1)Category/index.vue

运行结果演示:

这样,当切换路由的时候,接口只有一个了。
6、一级分类-使用逻辑函数拆分业务
在代码实现之前,需要考虑以下三个问题:
什么是使用逻辑函数拆分业务?
为什么要使用逻辑函数来对业务进行拆分?
怎么拆分?
在项目开发中,我们会遇到这样一个问题。有一些独立的业务代码,为了方便后去维护它们,我们需要将其拆分出来,封装成一个独立的函数,后面需要维护哪一块代码,直接找到对应的函数来进行维护即可,这样做,可以答复提升工作效率。
实现步骤如下:

1)逻辑封装时一个拆分再组合的过程,函数以use打头,内部封装逻辑。

2)把index.vue中与banner和category相关的逻辑分别拆分出去放到Usebanner.js和useCategory.js中,注意最后要return出去
Usebanner.js
import { ref , onMounted} from 'vue'
import { getBannerAPI } from '@/apis/home'
export function useBanner() {
  const bannerList = ref([])
const getBanner = async () => {
  const res = await getBannerAPI({
    distributionSite : '2'
  })
  
  console.log(res)
  bannerList.value = res.result
}
onMounted(() => {
  getBanner()
})
return {
  bannerList
}
}
useCategory.js
import { ref,onMounted } from 'vue'
import { getCategoryAPI } from '@/apis/category'
import { onBeforeRouteUpdate  } from 'vue-router'
import {useRoute } from 'vue-router'
const route = useRoute()
export function useCategory() {
const categoryData = ref([])
const getCategory = async (id= route.params.id) => {
  const res = await getCategoryAPI(id)
  categoryData.value = res.result
  console.log(res)
}
onMounted(()=>getCategory())
//路由参数变化的时候,可以把分类数据接口重新发送
onBeforeRouteUpdate((to)=> {
  console.log('路由变化了')
  //存在的问题,使用最新的路由参数获取最新的分类数据
  console.log(to)
  getCategory(to.params.id)
})
return {
  categoryData
}
}
3)在index.vue中导入解构使用











