This commit is contained in:
liu
2026-07-01 21:05:42 +08:00
parent ee7ffcc1cc
commit 0ee14678b6
15 changed files with 831 additions and 30 deletions
+4 -2
View File
@@ -1,3 +1,5 @@
export default definePageConfig({
navigationBarTitleText: '首页'
})
navigationBarTitleText: '首页',
navigationStyle: 'custom',
enablePullDownRefresh: false,
})
+146
View File
@@ -0,0 +1,146 @@
/* ========================================
首页样式
======================================== */
.home-page {
min-height: 100vh;
background: #f7f8fa;
}
/* ========== 自定义导航栏 (毛玻璃) ========== */
.custom-navbar {
position: fixed;
top: 0;
left: 0;
right: 0;
z-index: 999;
background: rgba(255, 255, 255, 0.72);
backdrop-filter: blur(20px);
-webkit-backdrop-filter: blur(20px);
}
.navbar-content {
display: flex;
align-items: center;
padding: 0 24px;
.navbar-search {
flex: 1;
}
}
/* ========== 滚动区域 ========== */
.page-scroll {
height: 100vh;
}
/* ========== 轮播图区域 ========== */
.swiper-section {
padding: 20px 24px 0;
.banner-swiper {
height: 320px;
border-radius: 12px;
overflow: hidden;
}
.swiper-card {
position: relative;
width: 100%;
height: 100%;
border-radius: 12px;
overflow: hidden;
.banner-image {
width: 100%;
height: 100%;
}
.banner-title {
position: absolute;
bottom: 0;
left: 0;
right: 0;
padding: 24px 20px;
font-size: 30px;
font-weight: 500;
color: #fff;
background: linear-gradient(180deg, transparent 0%, rgba(0, 0, 0, 0.5) 100%);
border-radius: 0 0 12px 12px;
}
}
}
/* ========== 导航组 ========== */
.nav-section {
margin: 24px 24px;
background: #fff;
border-radius: 16px;
padding: 24px 12px 12px;
box-shadow: 0 2px 12px rgba(0, 0, 0, 0.04);
}
/* ========== 标签区域 ========== */
.tabs-section {
background: #fff;
border-radius: 16px;
overflow: hidden;
margin: 0 24px 20px;
.van-tabs__wrap {
border-radius: 16px 16px 0 0;
}
}
/* ========== 文章列表 ========== */
.article-list {
padding: 0 24px;
.article-item {
background: #fff;
border-radius: 16px;
padding: 24px;
margin-bottom: 16px;
box-shadow: 0 2px 12px rgba(0, 0, 0, 0.04);
transition: transform 0.2s;
&:active {
transform: scale(0.98);
}
}
.empty-tip {
text-align: center;
padding: 80px 0;
font-size: 28px;
color: #969799;
}
}
/* 底部安全距离 */
.bottom-safe {
height: 40px;
}
/* ========== 文章卡片通用样式 ========== */
.article-card {
.card-meta {
display: flex;
align-items: center;
font-size: 24px;
color: #969799;
.meta-source {
margin-right: 16px;
}
.meta-time {
margin-right: 16px;
}
.meta-read {
flex: 1;
text-align: right;
}
}
}
+161 -27
View File
@@ -1,34 +1,168 @@
import { View } from '@tarojs/components'
import { Button } from '@antmjs/vantui'
import { useState, useMemo } from 'react'
import Taro from '@tarojs/taro'
import { View, ScrollView } from '@tarojs/components'
import { Search, Swiper, SwiperItem, Grid, GridItem, Tabs, Tab, Image as VantImage } from '@antmjs/vantui'
import ArticleCard from '@/components/ArticleCard'
import { banners, navItems, articles } from '@/mock/articles'
import type { ArticleCategory } from '@/types/article'
import './index.less'
/** 获取状态栏和导航栏高度 */
function getNavBarHeight() {
const systemInfo = Taro.getSystemInfoSync()
const statusBarHeight = systemInfo.statusBarHeight || 20
// 微信小程序导航栏高度一般为 44px,总高度 = 状态栏 + 导航栏
const navBarHeight = 44
return {
statusBarHeight,
navBarHeight,
totalHeight: statusBarHeight + navBarHeight,
}
}
/** 分类标签映射 */
const TAB_LIST = [
{ title: '最新', value: 'latest' as ArticleCategory },
{ title: '推荐', value: 'recommend' as ArticleCategory },
{ title: '热点', value: 'hot' as ArticleCategory },
]
export default function Index() {
const [activeTab, setActiveTab] = useState(0)
const navBarHeight = useMemo(() => getNavBarHeight(), [])
/** 根据当前 tab 筛选文章 */
const filteredArticles = useMemo(() => {
const category = TAB_LIST[activeTab]?.value || 'latest'
return articles.filter((a) => a.category === category)
}, [activeTab])
/** 搜索 */
const handleSearch = () => {
Taro.navigateTo({ url: '/pages/search/index' })
}
/** 导航项点击 */
const handleNavClick = (item: { path: string; label: string }) => {
if (item.path) {
Taro.navigateTo({ url: item.path })
} else {
Taro.showToast({ title: `${item.label}即将上线`, icon: 'none' })
}
}
/** 文章点击 */
const handleArticleClick = (id: string) => {
Taro.navigateTo({ url: `/pages/article/index?id=${id}` })
}
return (
<View className='index'>
<View><Button type='primary'>Hello world!</Button></View>
<View>src/styles/index.less</View>
<View className='home-page'>
{/* ========== 自定义导航栏 (毛玻璃) ========== */}
<View
className='custom-navbar'
style={{ paddingTop: `${navBarHeight.statusBarHeight}px` }}
>
<View className='navbar-content' style={{ height: `${navBarHeight.navBarHeight}px` }}>
<View className='navbar-search'>
<Search
placeholder='搜索课程、资讯、活动...'
onFocus={handleSearch}
shape='round'
background='transparent'
/>
</View>
</View>
</View>
{/* 占位,补偿固定导航栏高度 */}
<View style={{ height: `${navBarHeight.totalHeight}px` }} />
{/* ========== 可滚动内容区 ========== */}
<ScrollView
className='page-scroll'
scrollY
enhanced
showScrollbar={false}
>
{/* ========== 卡片轮播图 ========== */}
<View className='swiper-section'>
<Swiper
className='banner-swiper'
paginationColor='rgba(255,255,255,0.5)'
height={220}
autoPlay={3000}
duration={500}
loop
>
{banners.map((banner) => (
<SwiperItem key={banner.id}>
<View className='swiper-card'>
<VantImage
className='banner-image'
src={banner.image}
fit='cover'
width='100%'
height='100%'
radius={12}
/>
<View className='banner-title'>{banner.title}</View>
</View>
</SwiperItem>
))}
</Swiper>
</View>
{/* ========== 导航组 2行 x 5列 ========== */}
<View className='nav-section'>
<Grid columnNum={5} border={false} gutter={8}>
{navItems.map((item) => (
<GridItem
key={item.id}
icon={item.icon}
text={item.label}
onClick={() => handleNavClick(item)}
/>
))}
</Grid>
</View>
{/* ========== 文章标签导航 (最新 / 推荐 / 热点) ========== */}
<View className='tabs-section'>
<Tabs
active={activeTab}
onChange={(e) => setActiveTab(e.detail.index)}
sticky
offsetTop={navBarHeight.totalHeight}
color='#1989fa'
titleActiveColor='#1989fa'
titleInactiveColor='#646566'
>
{TAB_LIST.map((tab) => (
<Tab key={tab.value} title={tab.title} />
))}
</Tabs>
</View>
{/* ========== 文章列表 ========== */}
<View className='article-list'>
{filteredArticles.map((article) => (
<View
key={article.id}
className='article-item'
onClick={() => handleArticleClick(article.id)}
>
<ArticleCard article={article} />
</View>
))}
{filteredArticles.length === 0 && (
<View className='empty-tip'></View>
)}
</View>
{/* 底部安全距离 */}
<View className='bottom-safe' />
</ScrollView>
</View>
)
}
// export default class Index extends Component {
// componentWillMount () { }
// componentDidMount () { }
// componentWillUnmount () { }
// componentDidShow () { }
// componentDidHide () { }
// render () {
// return (
// <View className='index'>
// <View><Button type='primary'>Hello world!</Button></View>
// <View>上面的按钮的颜色已经通过全局主题重写覆盖了,参见src/style/index.less</View>
// </View>
// )
// }
// }