Browse Source

feat(index): 实现Header组件吸顶效果和轮播图触摸优化

- 添加Sticky组件实现Header吸顶功能
- 优化轮播图触摸事件,防止与页面滚动冲突
- 调整轮播图容器样式,确保手势操作流畅
- 更新Header组件结构以支持粘性布局
- 修复Banner组件中图片列表的key属性问题
- 移除不必要的状态传递和冗余代码
master
科技小王子 2 weeks ago
parent
commit
aa879f0062
  1. 12
      src/pages/index/Banner.tsx
  2. 7
      src/pages/index/Header.scss
  3. 104
      src/pages/index/Header.tsx
  4. 26
      src/pages/index/index.scss
  5. 16
      src/pages/index/index.tsx
  6. 4
      src/pages/order/order.scss

12
src/pages/index/Banner.tsx

@ -98,7 +98,7 @@ const MyPage = () => {
return (
<View className="flex p-2 justify-between" style={{height: `${carouselHeight}px`}}>
{/* 左侧轮播图区域 */}
<View style={{width: '50%', height: '100%'}}>
<View style={{width: '50%', height: '100%'}} className="banner-swiper-container">
<Swiper
defaultValue={0}
height={carouselHeight}
@ -106,9 +106,10 @@ const MyPage = () => {
autoPlay
duration={3000}
style={{
height: `${carouselHeight}px`,
touchAction: 'pan-y'
height: `${carouselHeight}px`
}}
disableTouch={false}
touchAngle={"45"} // 关键修改:设置触摸角度阈值
>
{carouselData && carouselData?.imageList?.map((img, index) => (
<Swiper.Item key={index}>
@ -139,7 +140,7 @@ const MyPage = () => {
}}>
{
hotToday?.imageList?.map(item => (
<View className={'item flex flex-col mr-1'}>
<View className={'item flex flex-col mr-1'} key={item.url}>
<Image
width={70}
height={70}
@ -180,5 +181,4 @@ const MyPage = () => {
)
}
export default MyPage
export default MyPage

7
src/pages/index/Header.scss

@ -14,3 +14,10 @@
position: absolute;
z-index: 0;
}
/* 吸顶状态下的样式 */
.nutui-sticky--fixed {
.header-bg {
height: 100%;
}
}

104
src/pages/index/Header.tsx

@ -1,6 +1,6 @@
import {useEffect, useState} from "react";
import Taro from '@tarojs/taro';
import {Button, Space} from '@nutui/nutui-react-taro'
import {Button, Space, Sticky} from '@nutui/nutui-react-taro'
import {TriangleDown} from '@nutui/icons-react-taro'
import {Avatar, NavBar} from '@nutui/nutui-react-taro'
import {getUserInfo, getWxOpenId} from "@/api/layout";
@ -22,6 +22,7 @@ const Header = (props: any) => {
const [IsLogin, setIsLogin] = useState<boolean>(true)
const [statusBarHeight, setStatusBarHeight] = useState<number>()
const [stickyStatus, setStickyStatus] = useState<boolean>(false)
const reload = async () => {
Taro.getSystemInfo({
@ -166,53 +167,76 @@ const Header = (props: any) => {
})
}
// 处理粘性布局状态变化
const onStickyChange = (isSticky: boolean) => {
setStickyStatus(isSticky)
console.log('Header 粘性状态:', isSticky ? '已固定' : '取消固定')
}
// 获取小程序系统信息
const getSystemInfo = () => {
const systemInfo = Taro.getSystemInfoSync()
// 状态栏高度 + 导航栏高度 (一般为44px)
return (systemInfo.statusBarHeight || 0) + 44
}
useEffect(() => {
reload().then()
}, [])
return (
<>
<View className={'fixed top-0 header-bg'} style={{
height: !props.stickyStatus ? '180px' : `${(statusBarHeight || 0) + 44}px`,
paddingBottom: !props.stickyStatus ? '12px' : '0px'
}}>
{/* 只在非吸顶状态下显示搜索框 */}
{!props.stickyStatus && <MySearch statusBarHeight={statusBarHeight} />}
</View>
<NavBar
<Sticky
threshold={0}
onChange={onStickyChange}
style={{
marginTop: `${statusBarHeight}px`,
marginBottom: '0px',
backgroundColor: 'transparent'
}}
onBackClick={() => {
zIndex: 1000,
backgroundColor: stickyStatus ? '#03605c' : 'transparent',
transition: 'background-color 0.3s ease',
}}
left={
!IsLogin ? (
<View style={{display: 'flex', alignItems: 'center'}}>
<Button style={{color: '#ffffff'}} open-type="getPhoneNumber" onGetPhoneNumber={handleGetPhoneNumber}>
<Space>
<Avatar
size="22"
src={getWebsiteLogo()}
/>
<Text style={{color: '#ffffff'}}>{getWebsiteName()}</Text>
<TriangleDown size={9} className={'text-white'}/>
</Space>
</Button>
</View>
) : (
<View style={{display: 'flex', alignItems: 'center', gap: '8px'}}>
<Avatar
size="22"
src={getWebsiteLogo()}
/>
<Text className={'text-white'}>{getWebsiteName()}</Text>
<TriangleDown className={'text-white'} size={9}/>
</View>
)}>
{/*<QRLoginButton />*/}
</NavBar>
>
<View className={'header-bg'} style={{
height: !stickyStatus ? '180px' : `${(statusBarHeight || 0) + 44}px`,
paddingBottom: !stickyStatus ? '12px' : '0px'
}}>
{/* 只在非吸顶状态下显示搜索框 */}
{!stickyStatus && <MySearch statusBarHeight={statusBarHeight} />}
</View>
<NavBar
style={{
marginTop: `${statusBarHeight}px`,
marginBottom: '0px',
backgroundColor: 'transparent'
}}
onBackClick={() => {
}}
left={
!IsLogin ? (
<View style={{display: 'flex', alignItems: 'center'}}>
<Button style={{color: '#ffffff'}} open-type="getPhoneNumber" onGetPhoneNumber={handleGetPhoneNumber}>
<Space>
<Avatar
size="22"
src={getWebsiteLogo()}
/>
<Text style={{color: '#ffffff'}}>{getWebsiteName()}</Text>
<TriangleDown size={9} className={'text-white'}/>
</Space>
</Button>
</View>
) : (
<View style={{display: 'flex', alignItems: 'center', gap: '8px'}}>
<Avatar
size="22"
src={getWebsiteLogo()}
/>
<Text className={'text-white'}>{getWebsiteName()}</Text>
<TriangleDown className={'text-white'} size={9}/>
</View>
)}>
{/*<QRLoginButton />*/}
</NavBar>
</Sticky>
</>
)
}

26
src/pages/index/index.scss

@ -18,3 +18,29 @@ page {
height: 70px;
}
}
/* 轮播图容器样式,确保不阻止页面滚动 */
.banner-swiper-container {
touch-action: pan-y !important;
.nut-swiper {
touch-action: pan-y !important;
pointer-events: none; // 关键修改禁用Swiper的指针事件
.nut-swiper-item {
touch-action: pan-y !important;
pointer-events: none; // 关键修改禁用Swiper Item的指针事件
image {
pointer-events: auto; // 重新启用图片的指针事件以便点击功能正常
}
}
}
}
/* 吸顶状态下的样式 */
.nutui-sticky--fixed {
.header-bg {
height: 100%;
}
}

16
src/pages/index/index.tsx

@ -4,19 +4,16 @@ import Taro from '@tarojs/taro';
import {useShareAppMessage} from "@tarojs/taro"
import {useEffect, useState} from "react";
import {getShopInfo} from "@/api/layout";
import {Sticky} from '@nutui/nutui-react-taro'
import Menu from "./Menu";
import Banner from "./Banner";
import {checkAndHandleInviteRelation, hasPendingInvite} from "@/utils/invite";
import './index.scss'
// import GoodsList from "./GoodsList";
function Home() {
// 吸顶状态
// const [stickyStatus, setStickyStatus] = useState<boolean>(false)
// Tabs粘性状态
const [tabsStickyStatus, setTabsStickyStatus] = useState<boolean>(false)
const [_, setTabsStickyStatus] = useState<boolean>(false)
useShareAppMessage(() => {
// 获取当前用户ID,用于生成邀请链接
@ -157,20 +154,13 @@ function Home() {
return (
<>
{/* Header区域 - 根据Tabs粘性状态决定是否固定 */}
{tabsStickyStatus ? (
<Sticky threshold={0}>
<Header stickyStatus={tabsStickyStatus}/>
</Sticky>
) : (
<Header stickyStatus={tabsStickyStatus}/>
)}
{/* Header区域 - 现在由Header组件内部处理吸顶逻辑 */}
<Header />
<div className={'flex flex-col mt-12'}>
<Menu/>
<Banner/>
<BestSellers onStickyChange={handleTabsStickyChange}/>
{/*<GoodsList/>*/}
</div>
</>
)

4
src/pages/order/order.scss

@ -1,4 +0,0 @@
// 订单页面样式
.order-page {
// 订单相关样式
}
Loading…
Cancel
Save