1.热门推荐-准备工作
// 用defineProps获取页面参数,query
const query = defineProps<{type: string
}>()
const currHot = hotMap.find((v) => v.type === query.type)
// 动态设置标题
uni.setNavigationBarTitle({ title: currHot!.title })
</script>
2.获取热门推荐数据
PageParams & { subType: string } 交叉类型,基于原有类型上进行扩展,再作为当前数据类型
- 封装通用接口
import type { PageParams } from '@/types/global'
import { http } from '@/utils/http'// 拓展类型
type HotParams = PageParams & { subType: string }
export const getHotRecommendAPI = (url: string, data: HotParams) => {return http({method: 'GET',url,data,})
}
- 初始化调用
// 获取热门推荐数据
const getHotRecommendData = async () => {const res = await getHotRecommendAPI(currHot!.url)
}
// 页面加载时调用
onLoad(() => {getHotRecommendData()
})
3.类型定义
类型的复用
export type GuessItem = GoodsItemimport type { PageResult, GoodsItem } from './global'
/** 热门推荐 */
export type HotResult = {/** id信息 */id: string/** 活动图片 */bannerPicture: string/** 活动标题 */title: string/** 子类选项 */subTypes: SubTypeItem[]
}/** 热门推荐-子类选项 */
export type SubTypeItem = {/** 子类id */id: string/** 子类标题 */title: string/** 子类对应的商品集合 */goodsItems: PageResult<GoodsItem>
}type HotParams = PageParams & { subType: string }
export const getHotRecommendAPI = (url: string, data?: HotParams) => {return http<HotResult>({method: 'GET',url,data,})
}
4.渲染页面和Tab交互
- 渲染页面
// 推荐封面图
const bannnerPicture = ref('')
// 推荐选项
const subTypes = ref<SubTypeItem[]>([])
// 获取下标
const activeIndex = ref(0)
// 获取热门推荐数据
const getHotRecommendData = async () => {const res = await getHotRecommendAPI(currHot!.url)bannnerPicture.value = res.result.bannerPicturesubTypes.value = res.result.subTypes
}
- Tab交互
<textv-for="(item, index) in subTypes":key="item.id"class="text":class="{ active: index === activeIndex }"@tap="activeIndex = index">{{ item.title }}</text>
用v-show反复的切换更好而不用v-if 耗费性能
<!-- 推荐列表 --><scroll-viewv-for="(item, index) in subTypes":key="item.id"v-show="activeIndex === index"scroll-yclass="scroll-view"><view class="goods"><navigatorhover-class="none"class="navigator"v-for="goods in item.goodsItems.items":key="goods.id":url="`/pages/goods/goods?id=${goods.id}`"><image class="thumb" :src="goods.picture"></image><view class="name ellipsis">{{ goods.name }}</view><view class="price"><text class="symbol">¥</text><text class="number">{{ goods.price }}</text></view></navigator></view><view class="loading-text">正在加载...</view></scroll-view></view>
</template>
5.分页加载
- 滚动触底
- 获取当前选项
- 当前页码累加
- 调用API传参
- 当前数据追加
实现效果:
// 滚动触底
const onScrolltolower = async () => {//获取当前选项const currsubTypes = subTypes.value[activeIndex.value]// 当前页码累加currsubTypes.goodsItems.page++// 调用API传参const res = await getHotRecommendAPI(currHot!.url, {subType: currsubTypes.id,page: currsubTypes.goodsItems.page,pageSize: currsubTypes.goodsItems.pageSize,})// 新的列表选项const newSubTypes = res.result.subTypes[activeIndex.value]// 数组追加currsubTypes.goodsItems.items.push(...newSubTypes.goodsItems.items)
}
6.分页结束条件
分页条件
// 分页条件if (currsubTypes.goodsItems.page < currsubTypes.goodsItems.pages) {// 当前页码累加currsubTypes.goodsItems.page++} else {// 标志已结束currsubTypes.finish = truereturn uni.showToast({ title: '已经到底了' })}
标记已结束
修改一下:
// 给SubTypeItem 再加一个类型,可有可无加?
const subTypes = ref<(SubTypeItem & { finish?: boolean })[]>([])// 获取热门推荐数据
const getHotRecommendData = async () => {const res = await getHotRecommendAPI(currHot!.url, {subType: '912000341',// 技巧: 环境变量,开发环境,修改初始页面方便测试分页结果page: import.meta.env.DEV ? 30 : 1,pageSize: 10,})bannnerPicture.value = res.result.bannerPicturesubTypes.value = res.result.subTypes
}// 标志已结束currsubTypes.finish = truereturn uni.showToast({ title: '已经到底了' })
页面底部提示
<view class="loading-text">{{ item.finish ? '已经到底了' : '正在加载中...' }}</view>
技巧:
环境变量,开发环境,修改初始页面方便测试分页结果
page: import.meta.env.DEV ? 30 : 1,
7.准备工作
静态数据=>获取轮播图数据=>渲染轮播图
<script setup lang="ts">
import { getHomeBannerAPI } from '@/services/home'
import { BannerItem } from '@/types/home'
import { ref } from 'vue'
import { onLoad } from '@dcloudio/uni-app'
const bannerList = ref<BannerItem[]>([])
//获取轮播图数据
const getHomeBannerData = async () => {const res = await getHomeBannerAPI()
}
// 页面加载时调用
onLoad(() => {getHomeBannerData()
})
</script>
8.渲染一级分类和Tab交互
- 封装API
import { http } from '@/utils/http'
import { CategoryTopItem } from '@/types/category'export const getCategoryTopAPI = () => {return http<CategoryTopItem[]>({method: 'GET',url: '/category/top',})
}
- 初始化调用
// 获取分类列表数据
const getCategoryTopData = async () => {const res = await getCategoryTopAPI()
}// 页面加载时调用
onLoad(() => {getHomeBannerData()getCategoryTopData()
})
- 定义类型
// 获取分类列表数据
const cayegoryList = ref<CategoryTopItem[]>([])
const getCategoryTopData = async () => {const res = await getCategoryTopAPI()cayegoryList.value = res.result
}
- 渲染一级分类
<scroll-view class="primary" scroll-y><viewv-for="(item, index) in cayegoryList":key="item.id"class="item":class="{ active: index === activeIndex }">
- Tab交互
// 获取分类列表数据
const cayegoryList = ref<CategoryTopItem[]>([])
const activeIndex = ref(0)
const getCategoryTopData = async () => {const res = await getCategoryTopAPI()cayegoryList.value = res.result
}<scroll-view class="primary" scroll-y><viewv-for="(item, index) in cayegoryList":key="item.id"class="item":class="{ active: index === activeIndex }"@tap="activeIndex = index">
9.二级分类和商品渲染
- 提取当前二级分类数据
// 提取当前二级分类数据
const subCategoryList = computed(() => {return cayegoryList.value[activeIndex.value]?.children || []
})
- 渲染二级分类
- 渲染商品
<view class="panel" v-for="item in subCategoryList" :key="item.id"><view class="title"><text class="name">{{ item.name }}</text><navigator class="more" hover-class="none">全部</navigator></view><view class="section"><navigatorv-for="goods in item.goods":key="goods.id"class="goods"hover-class="none":url="`/pages/goods/goods?id=${goods.id}`"><image class="image" :src="goods.picture"></image><view class="name ellipsis">{{ goods.name }}</view><view class="price"><text class="symbol">¥</text><text class="number">{{ goods.price }}</text></view></navigator></view></view>