uniapp小兔新儿day2

发布时间:2026/6/8 1:34:20

uniapp小兔新儿day2 自定义导航栏参考效果自定义导航栏的样式需要适配不同的机型。操作步骤准备组件静态结构修改页面配置隐藏默认导航栏修改文字颜色样式适配 - 安全区域静态结构新建业务组件src/pages/index/components/CustomNavbar.vuescript setup langts // /script template view classnavbar !-- logo文字 -- view classlogo image classlogo-image src/static/images/logo.png/image text classlogo-text新鲜 · 亲民 · 快捷/text /view !-- 搜索条 -- view classsearch text classicon-search搜索商品/text text classicon-scan/text /view /view /template style langscss /* 自定义导航条 */ .navbar { background-image: url(/static/images/navigator_bg.png); background-size: cover; position: relative; display: flex; flex-direction: column; padding-top: 20px; .logo { display: flex; align-items: center; height: 64rpx; padding-left: 30rpx; padding-top: 20rpx; .logo-image { width: 166rpx; height: 39rpx; } .logo-text { flex: 1; line-height: 28rpx; color: #fff; margin: 2rpx 0 0 20rpx; padding-left: 20rpx; border-left: 1rpx solid #fff; font-size: 26rpx; } } .search { display: flex; align-items: center; justify-content: space-between; padding: 0 10rpx 0 26rpx; height: 64rpx; margin: 16rpx 20rpx; color: #fff; font-size: 28rpx; border-radius: 32rpx; background-color: rgba(255, 255, 255, 0.5); } .icon-search { ::before { margin-right: 10rpx; } } .icon-scan { font-size: 30rpx; padding: 15rpx; } } /style安全区域不同手机的安全区域不同适配安全区域能防止页面重要内容被遮挡。可通过uni.getSystemInfoSync()获取屏幕边界到安全区的距离。核心代码参考自定义导航配置// src/pages.json { path: pages/index/index, style: { navigationStyle: custom, // 隐藏默认导航 navigationBarTextStyle: white, navigationBarTitleText: 首页 } }组件安全区适配!-- src/pages/index/componets/CustomNavbar.vue -- script // 获取屏幕边界到安全区域距离 const { safeAreaInsets } uni.getSystemInfoSync() /script template !-- 顶部占位 -- view classnavbar :style{ paddingTop: safeAreaInsets?.top px } !-- ...省略 -- /view /template通用轮播组件参考效果小兔鲜儿项目中总共有两处广告位分别位于【首页】和【商品分类页】。轮播图组件需要在首页和分类页使用需要封装成通用组件。静态结构首页广告布局为独立的组件XtxSwiper位于的src/components目录中。该组件定义了list属性接收外部传入的数据内部通过小程序内置组件swiper展示首页广告的数据。轮播图组件静态结构src/components/XtxSwiper.vuescript setup langts import { ref } from vue const activeIndex ref(0) /script template view classcarousel swiper :circulartrue :autoplayfalse :interval3000 swiper-item navigator url/pages/index/index hover-classnone classnavigator image modeaspectFill classimage srchttps://pcapi-xiaotuxian-front-devtest.itheima.net/miniapp/uploads/slider_1.jpg /image /navigator /swiper-item swiper-item navigator url/pages/index/index hover-classnone classnavigator image modeaspectFill classimage srchttps://pcapi-xiaotuxian-front-devtest.itheima.net/miniapp/uploads/slider_2.jpg /image /navigator /swiper-item swiper-item navigator url/pages/index/index hover-classnone classnavigator image modeaspectFill classimage srchttps://pcapi-xiaotuxian-front-devtest.itheima.net/miniapp/uploads/slider_3.jpg /image /navigator /swiper-item /swiper !-- 指示点 -- view classindicator text v-for(item, index) in 3 :keyitem classdot :class{ active: index activeIndex } /text /view /view /template style langscss /* 轮播图 */ .carousel { height: 280rpx; position: relative; overflow: hidden; transform: translateY(0); background-color: #efefef; .indicator { position: absolute; left: 0; right: 0; bottom: 16rpx; display: flex; justify-content: center; .dot { width: 30rpx; height: 6rpx; margin: 0 8rpx; border-radius: 6rpx; background-color: rgba(255, 255, 255, 0.4); } .active { background-color: #fff; } } .navigator, .image { width: 100%; height: 100%; } } /style自动导入全局组件参考配置{ // 组件自动引入规则 easycom: { // 是否开启自动扫描 /components/$1/$1.vue 组件 autoscan: true, // 以正则方式自定义组件匹配规则 custom: { // uni-ui 规则如下配置 ^uni-(.*): dcloudio/uni-ui/lib/uni-$1/uni-$1.vue, // 以 Xtx 开头的组件在 components 目录中查找 ^Xtx(.*): /components/Xtx$1.vue } } }全局组件类型声明Volar 插件说明Vue Language Tools// src/types/components.d.ts import XtxSwiper from ./XtxSwiper.vue declare module vue { export interface GlobalComponents { XtxSwiper: typeof XtxSwiper } }版本升级新版 Volar 把declare module vue/runtime-core调整为declare module vue获取数据接口调用该业务功能对于前端来说比较简单只需调用后端提供的接口将获得的数据展现结合运营人员的营销策略跳转到对应的链接地址即可。接口地址/home/banner请求方式GET请求参数Query:字段名必须默认值备注distributionSite否1活动 banner 位置1 代表首页2 代表商品分类页默认为 1请求封装// 存放路径: src/services/home.ts import type { BannerItem } from /types/home /** * 首页-广告区域-小程序 * param distributionSite 广告区域展示位置投放位置 投放位置1为首页2为分类商品页 默认是1 */ export const getHomeBannerAPI (distributionSite 1) { return httpBannerItem[]({ method: GET, url: /home/banner, data: { distributionSite, }, }) }类型声明存放路径src/types/home.d.ts/** 首页-广告区域数据类型 */ export type BannerItem { /** 跳转链接 */ hrefUrl: string /** id */ id: string /** 图片链接 */ imgUrl: string /** 跳转类型 */ type: number }最后将获得的数据结合模板语法渲染到页面中。参考代码轮播图组件src\components\XtxSwiper.vuescript setup langts import type { BannerItem } from /types/home import { ref } from vue const activeIndex ref(0) // 当 swiper 下标发生变化时触发 const onChange: UniHelper.SwiperOnChange (ev) { // ! 非空断言主观上排除掉空值情况 activeIndex.value ev.detail.current } // 定义 props 接收 defineProps{ list: BannerItem[] }() /script template view classcarousel swiper :circulartrue :autoplayfalse :interval3000 changeonChange swiper-item v-foritem in list :keyitem.id navigator url/pages/index/index hover-classnone classnavigator image modeaspectFill classimage :srcitem.imgUrl/image /navigator /swiper-item /swiper !-- 指示点 -- view classindicator text v-for(item, index) in list :keyitem.id classdot :class{ active: index activeIndex } /text /view /view /template首页分类参考效果准备工作准备组件只有首页使用导入并使用组件设置首页底色为#F7F7F7静态结构前台类目布局为独立的组件CategoryPanel属于首页的业务组件存放到首页的components目录中。script setup langts // /script template view classcategory navigator classcategory-item hover-classnone url/pages/index/index v-foritem in 10 :keyitem image classicon srchttps://pcapi-xiaotuxian-front-devtest.itheima.net/miniapp/images/nav_icon_1.png /image text classtext居家/text /navigator /view /template style langscss /* 前台类目 */ .category { margin: 20rpx 0 0; padding: 10rpx 0; display: flex; flex-wrap: wrap; min-height: 328rpx; .category-item { width: 150rpx; display: flex; justify-content: center; flex-direction: column; align-items: center; box-sizing: border-box; .icon { width: 100rpx; height: 100rpx; } .text { font-size: 26rpx; color: #666; } } } /style获取数据接口调用该业务功能对于前端来说比较简单只需调用后端提供的接口将获得的数据展现。接口地址/home/category/mutli请求方式GET请求参数无请求封装// services/home.ts /** * 首页-前台分类-小程序 */ export const getHomeCategoryAPI () { return httpCategoryItem[]({ method: GET, url: /home/category/mutli, }) }数据类型/** 首页-前台类目数据类型 */ export type CategoryItem { /** 图标路径 */ icon: string /** id */ id: string /** 分类名称 */ name: string }最后将获得的数据结合模板语法渲染到页面中。参考代码src\pages\index\components\CategoryPanel.vuescript setup langts import type { CategoryItem } from /types/home // 定义 props 接收数据 defineProps{ list: CategoryItem[] }() /script template view classcategory navigator classcategory-item hover-classnone url/pages/index/index v-foritem in list :keyitem.id image classicon :srcitem.icon/image text classtext{{ item.name }}/text /navigator /view /template热门推荐热门推荐功能后端根据用户的消费习惯等信息向用户推荐的一系列商品前端负责展示这些商品展示给用户。参考效果静态结构热门推荐布局为独立的组件HotPanel属于首页的业务组件存放到首页的components目录中。script setup langts // /script template !-- 推荐专区 -- view classpanel hot view classitem v-foritem in 4 :keyitem view classtitle text classtitle-text特惠推荐/text text classtitle-desc精选全攻略/text /view navigator hover-classnone url/pages/hot/hot classcards image classimage modeaspectFit srchttps://pcapi-xiaotuxian-front-devtest.itheima.net/miniapp/uploads/goods_small_1.jpg /image image classimage modeaspectFit srchttps://pcapi-xiaotuxian-front-devtest.itheima.net/miniapp/uploads/goods_small_2.jpg /image /navigator /view /view /template style langscss /* 热门推荐 */ .hot { display: flex; flex-wrap: wrap; min-height: 508rpx; margin: 20rpx 20rpx 0; border-radius: 10rpx; background-color: #fff; .title { display: flex; align-items: center; padding: 24rpx 24rpx 0; font-size: 32rpx; color: #262626; position: relative; .title-desc { font-size: 24rpx; color: #7f7f7f; margin-left: 18rpx; } } .item { display: flex; flex-direction: column; width: 50%; height: 254rpx; border-right: 1rpx solid #eee; border-top: 1rpx solid #eee; .title { justify-content: start; } :nth-child(2n) { border-right: 0 none; } :nth-child(-n 2) { border-top: 0 none; } .image { width: 150rpx; height: 150rpx; } } .cards { flex: 1; padding: 15rpx 20rpx; display: flex; justify-content: space-between; align-items: center; } } /style获取数据接口调用该业务功能对于前端来说比较简单只需调用后端提供的接口将获得的数据展现。接口地址/home/hot/mutli请求方式GET请求参数Headers:字段名称是否必须默认值备注source-client是无后端程序区分接口调用者miniapp 代表小程序端成功响应结果字段名称数据类型备注idstringIDtitlestring推荐标题typenumber推荐类型altstring推荐说明picturesarray[string]图片集合[ 图片路径 ]类型声明/** 首页-热门推荐数据类型 */ export type HotItem { /** 说明 */ alt: string /** id */ id: string /** 图片集合[ 图片路径 ] */ pictures: string[] /** 跳转地址 */ target: string /** 标题 */ title: string /** 推荐类型 */ type: string }接口封装// services/home.ts /** * 首页-热门推荐-小程序 */ export const getHomeHotAPI () { return httpHotItem[]({ method: GET, url: /home/hot/mutli, }) }最后将获得的数据结合模板语法渲染到页面中。参考代码src\pages\index\components\HotPanel.vuescript setup langts import type { HotItem } from /types/home // 定义 props 接收数据 defineProps{ list: HotItem[] }() /script template !-- 推荐专区 -- view classpanel hot view classitem v-foritem in list :keyitem.id view classtitle text classtitle-text{{ item.title }}/text text classtitle-desc{{ item.alt }}/text /view navigator hover-classnone :url/pages/hot/hot?type${item.type} classcards image v-forsrc in item.pictures :keysrc classimage modeaspectFit :srcsrc /image /navigator /view /view /template猜你喜欢(重点难点)参考效果猜你喜欢功能后端根据用户的浏览记录等信息向用户随机推荐的一系列商品前端负责把商品在多个页面中展示。准备工作准备组件 (通用组件多页面使用)定义组件类型准备scroll-view滚动容器设置page和scroll-view样式静态结构猜你喜欢是一个通用组件XtxGuess多个页面会用到该组件存放到src/components目录中。全局组件类型// types/components.d.ts import XtxSwiper from /components/XtxSwiper.vue import XtxGuess from /components/XtxGuess.vue declare module vue { export interface GlobalComponents { XtxSwiper: typeof XtxSwiper XtxGuess: typeof XtxGuess } } // 组件实例类型 export type XtxGuessInstance InstanceTypetypeof XtxGuess获取数据接口调用该业务功能对于前端来说比较简单只需调用后端提供的接口将获得的数据展现。接口地址/home/goods/guessLike请求方式GET请求参数Query:字段名称是否必须默认值备注page否1分页的页码pageSize否10每页数据的条数请求封装// src/services/home.ts /** * 猜你喜欢-小程序 */ export const getHomeGoodsGuessLikeAPI (data?: PageParams) { return httpPageResultGuessItem({ method: GET, url: /home/goods/guessLike, data, }) }类型声明通用分页结果类型如下新建src/types/global.d.ts文件/** 通用分页结果类型 */ export type PageResultT { /** 列表数据 */ items: T[] /** 总条数 */ counts: number /** 当前页数 */ page: number /** 总页数 */ pages: number /** 每页条数 */ pageSize: number }猜你喜欢-商品类型如下存放到src/types/home.d.ts文件/** 猜你喜欢-商品类型 */ export type GuessItem { /** 商品描述 */ desc: string /** 商品折扣 */ discount: number /** id */ id: string /** 商品名称 */ name: string /** 商品已下单数量 */ orderNum: number /** 商品图片 */ picture: string /** 商品价格 */ price: number }通用分页参数类型如下存放到src/types/global.d.ts文件/** 通用分页参数类型 */ export type PageParams { /** 页码默认值为 1 */ page?: number /** 页大小默认值为 10 */ pageSize?: number }核心业务子组件内部获取数据父滚动触底需加载分页组件通讯子调父参考代码项目首页// pages/index/index.vue script setup langts import type { XtxGuessInstance } from /types/components import { ref } from vue // 获取猜你喜欢组件实例 const guessRef refXtxGuessInstance() // 滚动触底事件 const onScrolltolower () { guessRef.value?.getMore() } /script template !-- 滚动容器 -- scroll-view scroll-y scrolltoloweronScrolltolower !-- 猜你喜欢 -- XtxGuess refguessRef / /scroll-view /template猜你喜欢组件// src/components/XtxGuess.vue script setup langts import { getHomeGoodsGuessLikeAPI } from /services/home import type { PageParams } from /types/global import type { GuessItem } from /types/home import { onMounted, ref } from vue // 分页参数 const pageParams: RequiredPageParams { page: 1, pageSize: 10, } // 猜你喜欢的列表 const guessList refGuessItem[]([]) // 已结束标记 const finish ref(false) // 获取猜你喜欢数据 const getHomeGoodsGuessLikeData async () { // 退出分页判断 if (finish.value true) { return uni.showToast({ icon: none, title: 没有更多数据~ }) } const res await getHomeGoodsGuessLikeAPI(pageParams) // 数组追加 guessList.value.push(...res.result.items) // 分页条件 if (pageParams.page res.result.pages) { // 页码累加 pageParams.page } else { finish.value true } } // 重置数据 const resetData () { pageParams.page 1 guessList.value [] finish.value false } // 组件挂载完毕 onMounted(() { getHomeGoodsGuessLikeData() }) // 暴露方法 defineExpose({ resetData, getMore: getHomeGoodsGuessLikeData, }) /script template !-- 猜你喜欢 -- view classcaption text classtext猜你喜欢/text /view view classguess navigator classguess-item v-foritem in guessList :keyitem.id :url/pages/goods/goods image classimage modeaspectFill :srcitem.picture/image view classname {{ item.name }} /view view classprice text classsmall¥/text text{{ item.price }}/text /view /navigator /view view classloading-text {{ finish ? 没有更多数据~ : 正在加载... }} /view /template下拉刷新下拉刷新实际上是在用户操作下拉交互时重新调用接口然后将新获取的数据再次渲染到页面中。操作步骤基于scroll-view组件实现下拉刷新需要通过以下方式来实现下拉刷新的功能。配置refresher-enabled属性开启下拉刷新交互监听refresherrefresh事件判断用户是否执行了下拉操作配置refresher-triggered属性关闭下拉状态参考代码猜你喜欢组件定义重置数据的方法// src/components/XtxGuess.vue // 重置数据 const resetData () { pageParams.page 1 guessList.value [] finish.value false } // 暴露方法 defineExpose({ resetData, })首页触发下拉刷新// src/pages/index/index.vue script setup langts // 下拉刷新状态 const isTriggered ref(false) // 自定义下拉刷新被触发 const onRefresherrefresh async () { // 开启动画 isTriggered.value true // 重置猜你喜欢组件数据 guessRef.value?.resetData() // 加载数据 await Promise.all([getHomeBannerData(), getHomeCategoryData(), getHomeHotData()]) // 关闭动画 isTriggered.value false } /script !-- 滚动容器 -- scroll-view refresher-enabled refresherrefreshonRefresherrefresh :refresher-triggeredisTriggered classscroll-view scroll-y …省略 /scroll-view骨架屏骨架屏是页面的一个空白版本通常会在页面完全渲染之前通过一些灰色的区块大致勾勒出轮廓待数据加载完成后再替换成真实的内容。参考效果骨架屏作用是缓解用户等待时的焦虑情绪属于用户体验优化方案。生成骨架屏微信开发者工具提供了自动生成骨架屏代码的能力。使用时需要把自动生成的xxx.skeleton.wxml和xxx.skeleton.wxss封装成vue组件。

相关新闻