children:[
{
path: '',
component: Home
},
{
path: 'category/:id',
component: Category
}
]
重构Layout/LayoutHeader.vue
<ul class="app-header-nav">
<li class="home">
<RouterLink to="/">首页</RouterLink>
</li>
<li v-for="item in categoryList" :key="item.id">
<RouterLink :to="`/category/${item.id}`">{{item.name}}</RouterLink>
</li>
</ul>
<li v-for="item in categoryList" :key="item.id">
<RouterLink active-class="active" :to="`/category/${item.id}`">{{item.name}}</RouterLink>
</li>
样式
.active {
color: $xtxColor;
border-bottom: 1px solid $xtxColor;
}
##步骤4:重构LayoutFixed.vue
<li v-for="item in categoryList" :key="item.id">
<RouterLink active-class="active" :to="`/category/${item.id}`">{{item.name}}</RouterLink>
</li>
<script setup>
</script>
<template>
<div class="top-category">
<div class="container m-top-20">
<!-- 面包屑 -->
<div class="bread-container">
<el-breadcrumb separator=">">
<el-breadcrumb-item :to="{ path: '/' }">首页</el-breadcrumb-item>
<el-breadcrumb-item>居家</el-breadcrumb-item>
</el-breadcrumb>
</div>
</div>
</div>
</template>
<style scoped lang="scss">
.top-category {
h3 {
font-size: 28px;
color: #666;
font-weight: normal;
text-align: center;
line-height: 100px;
}
.sub-list {
margin-top: 20px;
background-color: #fff;
ul {
display: flex;
padding: 0 32px;
flex-wrap: wrap;
li {
width: 168px;
height: 160px;
a {
text-align: center;
display: block;
font-size: 16px;
img {
width: 100px;
height: 100px;
}
p {
line-height: 40px;
}
&:hover {
color: $xtxColor;
}
}
}
}
}
.ref-goods {
background-color: #fff;
margin-top: 20px;
position: relative;
.head {
.xtx-more {
position: absolute;
top: 20px;
right: 20px;
}
.tag {
text-align: center;
color: #999;
font-size: 20px;
position: relative;
top: -20px;
}
}
.body {
display: flex;
justify-content: space-around;
padding: 0 40px 30px;
}
}
.bread-container {
padding: 25px 0;
}
}
</style>
创建apis/category.js
import http from "@/utils/http";
/**
* @description: 根据id获得一级分类对象信息
* @param {*} id 分类id
* @return {*}
*/
export function getTopCategoryAPI(id){
return http.get('/category',{params:{id}});
}
<script setup>
import {getTopCategoryAPI} from '@/apis/category'
import {useRoute} from "vue-router";
import {onMounted, onUpdated, ref} from "vue";
const categoryData = ref({})
const route = useRoute()
const getCategory = async () => {
// 如何在setup中获取路由参数 useRoute() -> route 等价于this.$route
//console.log(route.params.id);
const res = await getTopCategoryAPI(route.params.id)
categoryData.value = res.result
}
onMounted(()=>getCategory())
</script>
<template>
<div class="top-category">
<div class="container m-top-20">
<!-- 面包屑 -->
<div class="bread-container">
<el-breadcrumb separator=">">
<el-breadcrumb-item :to="{ path: '/' }">首页</el-breadcrumb-item>
<el-breadcrumb-item>{{ categoryData.name }}</el-breadcrumb-item>
</el-breadcrumb>
</div>
</div>
</div>
</template>
修改apis/home.js
/**
* @description: 获取轮播图
* @param distributionSite='1' 首页 '2'表示分类页面
* @return {*}
*/
export function getBannerAPI(distributionSite='1'){
return http.get('/home/banner',{params:{distributionSite}});
}
<script setup>
...
//轮播图
const bannerList = ref([]);
const getBanner = async () => {
const res = await getBannerAPI('2');
bannerList.value = res.result;
}
onMounted(()=>getBanner());
</script>
<template>
<div class="top-category">
<div class="container m-top-20">
<!-- 面包屑 -->
<div class="bread-container">
<el-breadcrumb separator=">">
<el-breadcrumb-item :to="{ path: '/' }">首页</el-breadcrumb-item>
<el-breadcrumb-item>{{ categoryData.name }}</el-breadcrumb-item>
</el-breadcrumb>
</div>
<!-- 轮播图 -->
<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>
</div>
</div>
</template>
<style scoped lang="scss">
...
.home-banner {
width: 1240px;
height: 500px;
margin: 0 auto;
img {
width: 100%;
height: 500px;
}
}
</style>
重构Category/index.vue
<!-- 分类产品图片 -->
<div class="sub-list">
<h3>全部分类</h3>
<ul>
<li v-for="i in categoryData.children" :key="i.id">
<RouterLink to="/">
<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" :good="good" :key="good.id" />
</div>
</div>
数据结构分析
缓存问题:当路由path一样,参数不同的时候会选择直接复用路由对应的组件
解决方法
方式1:给router-view添加key ,破坏复用机制,强制销毁重建
重构Layout/index.vue
<template>
<LayoutFixed></LayoutFixed>
<LayoutNav></LayoutNav>
<LayoutHeader></LayoutHeader>
<RouterView :key="$route.fullPath"/>
<LayoutFooter></LayoutFooter>
</template>
方式2:使用 onBeforeRouteUpdate钩子函数,做精确更新
重构Category/index.vue
import {useRoute,onBeforeRouteUpdate} from "vue-router";
onBeforeRouteUpdate((to)=>{
getCategory(to.params.id)
})
点击新的链接,页面切换到最顶端
重构router/index.js
const router = createRouter({
...
//定制路由滚动行为
scrollBehavior(){
return{
top:0
}
}
基本思想:把组件内独立的业务逻辑通过
useXXX
函数做封装处理,在组件中做组合使用
实现步骤:
1. 按照业务声明以 `use` 打头的逻辑函数
2. 把独立的业务逻辑封装到各个函数内部
3. 函数内部把组件中需要用到的数据或者方法return出去
4. 在组件中调用函数把数据或者方法组合回来使用
创建composables/useCategory.js
import {onBeforeRouteUpdate, useRoute} from "vue-router";
import {getTopCategoryAPI} from "@/apis/category";
export function useCategory(){
const categoryData = ref({})
const route = useRoute()
const getCategory = async (id) => {
// 如何在setup中获取路由参数 useRoute() -> route 等价于this.$route
//console.log(route.params.id);
const res = await getTopCategoryAPI(route.params.id)
categoryData.value = res.result
}
onMounted(()=>getCategory())
onBeforeRouteUpdate((to)=>{
getCategory(to.params.id)
})
return{
categoryData
}
}
import {getBannerAPI} from "@/apis/home";
export function useBanner(){
const bannerList = ref([])
const getBanner = async () => {
const res = await getBannerAPI('2')
bannerList.value = res.result
}
onMounted(()=>{
getBanner()
})
return {
bannerList
}
}
<script setup>
import GoodsItem from "@/views/Home/components/GoodsItem.vue";
import {useBanner} from "@/views/Category/composables/useBanner";
import {useCategory} from "@/views/Category/composables/useCategory";
//面包屑及一级分类数据
const {categoryData} = useCategory();
//轮播图
const {bannerList} = useBanner();
</script>