Browse Source

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

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

10
src/pages/index/Banner.tsx

@ -98,7 +98,7 @@ const MyPage = () => {
return ( return (
<View className="flex p-2 justify-between" style={{height: `${carouselHeight}px`}}> <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 <Swiper
defaultValue={0} defaultValue={0}
height={carouselHeight} height={carouselHeight}
@ -106,9 +106,10 @@ const MyPage = () => {
autoPlay autoPlay
duration={3000} duration={3000}
style={{ style={{
height: `${carouselHeight}px`,
touchAction: 'pan-y'
height: `${carouselHeight}px`
}} }}
disableTouch={false}
touchAngle={"45"} // 关键修改:设置触摸角度阈值
> >
{carouselData && carouselData?.imageList?.map((img, index) => ( {carouselData && carouselData?.imageList?.map((img, index) => (
<Swiper.Item key={index}> <Swiper.Item key={index}>
@ -139,7 +140,7 @@ const MyPage = () => {
}}> }}>
{ {
hotToday?.imageList?.map(item => ( hotToday?.imageList?.map(item => (
<View className={'item flex flex-col mr-1'}>
<View className={'item flex flex-col mr-1'} key={item.url}>
<Image <Image
width={70} width={70}
height={70} height={70}
@ -181,4 +182,3 @@ const MyPage = () => {
} }
export default MyPage export default MyPage

7
src/pages/index/Header.scss

@ -14,3 +14,10 @@
position: absolute; position: absolute;
z-index: 0; 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 {useEffect, useState} from "react";
import Taro from '@tarojs/taro'; 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 {TriangleDown} from '@nutui/icons-react-taro'
import {Avatar, NavBar} from '@nutui/nutui-react-taro' import {Avatar, NavBar} from '@nutui/nutui-react-taro'
import {getUserInfo, getWxOpenId} from "@/api/layout"; import {getUserInfo, getWxOpenId} from "@/api/layout";
@ -22,6 +22,7 @@ const Header = (props: any) => {
const [IsLogin, setIsLogin] = useState<boolean>(true) const [IsLogin, setIsLogin] = useState<boolean>(true)
const [statusBarHeight, setStatusBarHeight] = useState<number>() const [statusBarHeight, setStatusBarHeight] = useState<number>()
const [stickyStatus, setStickyStatus] = useState<boolean>(false)
const reload = async () => { const reload = async () => {
Taro.getSystemInfo({ 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(() => { useEffect(() => {
reload().then() reload().then()
}, []) }, [])
return ( 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={{ 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; 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 {useShareAppMessage} from "@tarojs/taro"
import {useEffect, useState} from "react"; import {useEffect, useState} from "react";
import {getShopInfo} from "@/api/layout"; import {getShopInfo} from "@/api/layout";
import {Sticky} from '@nutui/nutui-react-taro'
import Menu from "./Menu"; import Menu from "./Menu";
import Banner from "./Banner"; import Banner from "./Banner";
import {checkAndHandleInviteRelation, hasPendingInvite} from "@/utils/invite"; import {checkAndHandleInviteRelation, hasPendingInvite} from "@/utils/invite";
import './index.scss' import './index.scss'
// import GoodsList from "./GoodsList";
function Home() { function Home() {
// 吸顶状态 // 吸顶状态
// const [stickyStatus, setStickyStatus] = useState<boolean>(false) // const [stickyStatus, setStickyStatus] = useState<boolean>(false)
// Tabs粘性状态 // Tabs粘性状态
const [tabsStickyStatus, setTabsStickyStatus] = useState<boolean>(false)
const [_, setTabsStickyStatus] = useState<boolean>(false)
useShareAppMessage(() => { useShareAppMessage(() => {
// 获取当前用户ID,用于生成邀请链接 // 获取当前用户ID,用于生成邀请链接
@ -157,20 +154,13 @@ function Home() {
return ( return (
<> <>
{/* Header区域 - 根据Tabs粘性状态决定是否固定 */}
{tabsStickyStatus ? (
<Sticky threshold={0}>
<Header stickyStatus={tabsStickyStatus}/>
</Sticky>
) : (
<Header stickyStatus={tabsStickyStatus}/>
)}
{/* Header区域 - 现在由Header组件内部处理吸顶逻辑 */}
<Header />
<div className={'flex flex-col mt-12'}> <div className={'flex flex-col mt-12'}>
<Menu/> <Menu/>
<Banner/> <Banner/>
<BestSellers onStickyChange={handleTabsStickyChange}/> <BestSellers onStickyChange={handleTabsStickyChange}/>
{/*<GoodsList/>*/}
</div> </div>
</> </>
) )

4
src/pages/order/order.scss

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