fix(index): 修复首页轮播图显示与高度自适应问题
- 解决首页轮播图仅显示第一张图片的问题,支持广告位多图展开显示 - 通过 flatMap 展开广告位所有图片为独立轮播项,兼容单图老数据 - 轮播图点击跳转逻辑按广告位路径保持不变 - 获取轮播容器实际宽度,计算轮播高度自适应,替代固定 160px 高度 - 根据后台广告位宽高比计算轮播图展示高度,无效数据时回退到默认高度 - 轮播容器新增类名便于 DOM 选择和尺寸测量 - 轮播图及占位区高度均采用动态计算结果,适配不同设备屏幕宽度
This commit is contained in:
@@ -243,3 +243,25 @@
|
||||
- 编译验证:`npx taro build --type weapp` 14.89s 成功
|
||||
- 设计稿预览:`.workbuddy/sms-login-preview.html`(按 375×812 真机尺寸渲染的 mockup,可直接浏览器打开看)
|
||||
- 业务规则:login/register/sms-login 三个页面已统一视觉风格(同一套渐变 + 圆形 logo + 大字标题 + 白色卡片),后续新增 passport 类页面照搬这一套即可
|
||||
|
||||
## 修复首页轮播图只显示一张的问题
|
||||
- 文件:`src/pages/index/index.tsx`
|
||||
- 现象:后台一个广告位下配置了 3 张图片,但小程序首页轮播只显示第一张
|
||||
- 根因:原代码把每个 `CmsAd` 作为一个 `SwiperItem`,图片只取 `item.imageList?.[0]?.url`,所以无论后台配几张都只渲染首图
|
||||
- 修复:
|
||||
- 新增 `bannerSlides`:用 `flatMap` 把每个广告位下的 `imageList` 全部展开成独立轮播项,key 用 `adId-uid`(无 uid 则 fallback 到索引)
|
||||
- 保留 `item.image` 单图兜底逻辑,兼容只配单张图片的老数据
|
||||
- 渲染 `SwiperItem` 改为遍历 `bannerSlides`,点击跳转仍使用对应广告位的 `path`
|
||||
- 验证:代码逻辑走查通过;项目原有 `npx tsc --noEmit` 的 `@tarojs/taro` 类型定义错误与本次修改无关
|
||||
|
||||
## 首页轮播图高度改为按后台 width/height 自适应
|
||||
- 文件:`src/pages/index/index.tsx`
|
||||
- 原状:`Swiper` 的 `height` 固定写死 `160px`,与后台广告位配置脱节
|
||||
- 修复:
|
||||
- 新增 `bannerWrapWidth` 状态,页面渲染后用 `Taro.createSelectorQuery().select('.index-banner-wrap').boundingClientRect()` 获取容器实际宽度
|
||||
- 新增 `bannerHeight`(useMemo):取第一个带有效 `width/height` 的广告位,按 `容器宽度 * (height / width)` 计算高度;无值或解析失败则 fallback `160px`
|
||||
- 轮播容器增加 `index-banner-wrap` 类名用于选择器查询
|
||||
- `Swiper` 和「暂无轮播图」占位区的高度都改用 `bannerHeight`
|
||||
- 注意:宽度仍由容器 `w-full` + `mx-3` 边距控制,不直接套用后台 `width` 像素值;高度按比例缩放适配不同屏幕
|
||||
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import React, { useState, useEffect, useCallback, useRef } from 'react'
|
||||
import React, { useState, useEffect, useCallback, useRef, useMemo } from 'react'
|
||||
import { View, Text, ScrollView, Swiper, SwiperItem, Image } from '@tarojs/components'
|
||||
import Taro, { useDidShow } from '@tarojs/taro'
|
||||
import { useUser } from '@/hooks/useUser'
|
||||
@@ -26,6 +26,7 @@ definePageConfig({
|
||||
const IndexPage: React.FC = () => {
|
||||
const { user, isLoggedIn } = useUser()
|
||||
const [banners, setBanners] = useState<CmsAd[]>([])
|
||||
const [bannerWrapWidth, setBannerWrapWidth] = useState(0)
|
||||
const [announcements, setAnnouncements] = useState<CmsArticle[]>([])
|
||||
const [hotProducts, setHotProducts] = useState<ShopGoods[]>([])
|
||||
const [loading, setLoading] = useState(true)
|
||||
@@ -190,6 +191,31 @@ const IndexPage: React.FC = () => {
|
||||
}
|
||||
}
|
||||
|
||||
// 获取轮播容器实际宽度,用于根据后台 width/height 计算比例高度
|
||||
useEffect(() => {
|
||||
if (bannerWrapWidth > 0) return
|
||||
const timer = setTimeout(() => {
|
||||
const query = Taro.createSelectorQuery()
|
||||
query.select('.index-banner-wrap').boundingClientRect((rect) => {
|
||||
if (rect && rect.width > 0) {
|
||||
setBannerWrapWidth(rect.width)
|
||||
}
|
||||
}).exec()
|
||||
}, 0)
|
||||
return () => clearTimeout(timer)
|
||||
}, [bannerWrapWidth])
|
||||
|
||||
// 根据广告位后台返回的 width/height 计算轮播区域高度(无值则 fallback 160px)
|
||||
const bannerHeight = useMemo(() => {
|
||||
if (bannerWrapWidth <= 0) return 160
|
||||
const firstAd = banners.find(b => b.width && b.height)
|
||||
if (!firstAd) return 160
|
||||
const w = parseInt(firstAd.width || '0', 10)
|
||||
const h = parseInt(firstAd.height || '0', 10)
|
||||
if (!w || !h || w <= 0 || h <= 0) return 160
|
||||
return Math.round(bannerWrapWidth * (h / w))
|
||||
}, [bannerWrapWidth, banners])
|
||||
|
||||
// 轮播图数据:每个广告位下的所有图片都作为独立轮播项
|
||||
const bannerSlides = banners.flatMap(item =>
|
||||
(item.imageList && item.imageList.length > 0)
|
||||
@@ -233,13 +259,13 @@ const IndexPage: React.FC = () => {
|
||||
|
||||
<ScrollView scrollY style={{ height: scrollHeight }}>
|
||||
{/* 轮播图 */}
|
||||
<View className='mx-3 mt-2 rounded-lg overflow-hidden'>
|
||||
<View className='mx-3 mt-2 rounded-lg overflow-hidden index-banner-wrap'>
|
||||
{bannerSlides.length > 0 ? (
|
||||
<Swiper
|
||||
autoplay
|
||||
interval={3000}
|
||||
className='rounded-lg'
|
||||
style={{ height: '160px' }}
|
||||
style={{ height: `${bannerHeight}px` }}
|
||||
>
|
||||
{bannerSlides.map(slide => (
|
||||
<SwiperItem key={slide.key}>
|
||||
@@ -255,7 +281,7 @@ const IndexPage: React.FC = () => {
|
||||
))}
|
||||
</Swiper>
|
||||
) : (
|
||||
<View className='w-full bg-green-50 flex items-center justify-center' style={{ height: '160px' }}>
|
||||
<View className='w-full bg-green-50 flex items-center justify-center' style={{ height: `${bannerHeight}px` }}>
|
||||
<Text className='text-gray-400 text-sm'>暂无轮播图</Text>
|
||||
</View>
|
||||
)}
|
||||
|
||||
Reference in New Issue
Block a user