1.结合Ant Design Mobile 实现一个底部tab栏切换(配合路由使用)
配置路由
import { Navigate } from "react-router-dom";
import Layout from '../pages/layout'
import Index from '../pages/index/index'
import Cart from '../pages/cart/cart'
import Shop from '../pages/shop/shop'
import My from '../pages/my/my'
import Detail from '../pages/detail/detail'
import Login from '../pages/login/login'
const routerList = [
{ path: '/', element: <Navigate to='/layout/index'></Navigate> },
{
path: "layout", element: <Layout></Layout>, children: [
{ path: 'index', element: <Index></Index> },
{ path: 'cart', element: <Cart></Cart> },
{ path: 'shop', element: <Shop></Shop> },
{ path: 'my', element: <My></My> },
{ path: 'detail', element: <Detail></Detail> },
]
},
{
path: 'login', element: <Login></Login>
}
]
export default routerList
layout页面
import React from 'react'
import { TabBar } from 'antd-mobile'
import { useLocation, Outlet, useNavigate } from 'react-router-dom'
import {
AppOutline,
MessageOutline,
UnorderedListOutline,
UserOutline,
} from 'antd-mobile-icons'
import './layout.css'
function Bottom() {
const nav = useNavigate()
const location = useLocation()
const { pathname } = location
const setRouteActive = (value) => {
nav(value)
}
const tabs = [
{
key: 'index',
title: '首页',
icon: <AppOutline />,
},
{
key: 'cart',
title: '分类',
icon: <UnorderedListOutline />,
},
{
key: 'shop',
title: '购物车',
icon: <MessageOutline />,
},
{
key: 'my',
title: '我的',
icon: <UserOutline />,
},
]
return (
<TabBar activeKey={pathname} onChange={value => setRouteActive(value)} >
{tabs.map(item => (
<TabBar.Item key={item.key} icon={item.icon} title={item.title} className="active" />
))}
</TabBar>
)
}
export default () => {
return (
<div className="app">
<div className="body">
<Outlet></Outlet>
</div>
<div className="bottom">
<Bottom />
</div>
</div>
)
}
layout页面样式
.app {
height: 100vh;
display: flex;
flex-direction: column;
}
.body {
flex: 1;
display: flex;
}
.bottom {
border-top: solid 1px var(--adm-color-border);
position: fixed;
bottom: 0;
width: 100%;
background-color: white;
}
.active:hover {
color: red;
}
首页+回到顶部效果(附加动画)
import React from 'react';
import { Swiper, Image } from 'react-vant';
import { images } from './demo/images.ts';
import { useState, useEffect } from 'react';
import axios from '../../server/request'
import './index.css'
function Index() {
const [showTrue, setShowTrue] = useState(false)
const [data, setData] = useState([])
useEffect(() => {
getGoodList()
const handleScrool = () => {
//滑动的距离大于 0 时,显示按钮
document.documentElement.scrollTop > 0 ? setShowTrue(true) : setShowTrue(false)
}
document.addEventListener('scroll', handleScrool)
return () => document.removeEventListener('scroll', handleScrool)
}, [showTrue])
// 回到顶部
const backTop = () => {
let timer = setInterval(() => {
//获取滑动的距离
let top = document.documentElement.scrollTop || document.body.scrollTop
window.scrollTo(0, top - top / 5) //设置返回时 是缓慢带有动画的
if (top === 0) {
clearInterval(timer)
}
}, 30)
}
function getGoodList() {
axios.get('/getgoodlist').then(res => {
console.log(res, '4444444')
setData(res.data)
})
}
return (
<div className="index">
<div className="demo-swiper">
<Swiper>
{images.map((image) => (
<Swiper.Item key={image}>
<Image src={image} style={{ height: "250px" }} />
</Swiper.Item>
))}
</Swiper>
</div>
<div className="nav">
<ul>
<li>签到</li>
<li>礼券</li>
<li>砍价</li>
<li>专栏</li>
</ul>
</div>·
<div className="second-swiper">
<h2>精选主题</h2>
<div className="demo-swiper">
<Swiper slideSize={80}> {images.map((image) => (
<Swiper.Item key={image}>
<div className='images'>
<Image src={image} style={{ height: "250px", }} />
</div>
</Swiper.Item>
))}</Swiper>
</div>
</div>
<div className="content">
<h2>人气推荐</h2>
<ul>
{
data.map((item, index) => {
return (
<li key={index}>
<img src={item.pic} alt="" width="100%" style={{ height: "200px" }} />
<p>{item.title}</p>
<p style={{ color: 'red' }}>¥{item.price}</p>
</li>
)
})
}
</ul>
</div>
<div className="backTop" style={{ display: showTrue ? 'block' : 'none' }} onClick={backTop}>返回顶部</div>
</div>
);
}
export default Index
分类页面
import { Search } from 'react-vant';
import React, { useEffect, useState } from 'react';
import { Sidebar } from 'react-vant';
import axios from '../../server/request';
import './style.css'
import { ProductCard } from 'react-vant';
export default function Cart() {
const [value, setValue] = useState('');
const [active, setActive] = useState(0);
const [data, setData] = useState([])
useEffect(() => {
getGoodList(0)
}, [])
function getGoodList(v) {
setActive(v)
axios.get('/getGood?type=' + v).then(res => {
console.log(res.data, '5555555555')
setData(res.data)
})
}
return (
<div className='cart'>
<div className="cart-search">
<Search value={value} onChange={setValue} placeholder="请输入搜索关键词" />
</div>
<div className="cart-content">
<Sidebar
value={active}
onChange={(v) => {
getGoodList(v)
}}
>
<Sidebar.Item contentStyle={{ backgroundColor: '#fff', padding: '18px 10px' }} title="男装">
{
data.map(item => {
return (
<div>
<ProductCard
key={item._id}
price={item.price}
title={item.name}
thumb={item.img}
/>
</div>
)
})
}
</Sidebar.Item>
<Sidebar.Item contentStyle={{ backgroundColor: '#fff', padding: '18px 10px' }} title="女装">
{
data.map(item => {
return (
<div>
<ProductCard
key={item._id}
price={item.price}
title={item.name}
thumb={item.img}
/>
</div>
)
})
}
</Sidebar.Item>
<Sidebar.Item contentStyle={{ backgroundColor: '#fff', padding: '18px 10px' }} title="童装">
{
data.map(item => {
return (
<div>
<ProductCard
key={item._id}
price={item.price}
title={item.name}
thumb={item.img}
/>
</div>
)
})
}
</Sidebar.Item>
</Sidebar>
</div>
</div>
)
}
详情页面