This commit is contained in:
HuaYu 2023-01-18 20:57:54 +08:00
parent f1a6add174
commit f47616a7b8
10 changed files with 351 additions and 55 deletions

40
package-lock.json generated
View File

@ -18,6 +18,7 @@
"react-dom": "^18.2.0", "react-dom": "^18.2.0",
"react-router-dom": "^6.6.2", "react-router-dom": "^6.6.2",
"react-scripts": "5.0.1", "react-scripts": "5.0.1",
"react-virtualized": "^9.22.3",
"web-vitals": "^2.1.4" "web-vitals": "^2.1.4"
} }
}, },
@ -5743,6 +5744,14 @@
"wrap-ansi": "^7.0.0" "wrap-ansi": "^7.0.0"
} }
}, },
"node_modules/clsx": {
"version": "1.2.1",
"resolved": "https://registry.npmmirror.com/clsx/-/clsx-1.2.1.tgz",
"integrity": "sha512-EcR6r5a8bj6pu3ycsa/E/cKVGuTgZJZdsyUYHOksG/UHIiKfjxzRxYJpyVBwYaQeOvghal9fcc4PidlgzugAQg==",
"engines": {
"node": ">=6"
}
},
"node_modules/co": { "node_modules/co": {
"version": "4.6.0", "version": "4.6.0",
"resolved": "https://registry.npmmirror.com/co/-/co-4.6.0.tgz", "resolved": "https://registry.npmmirror.com/co/-/co-4.6.0.tgz",
@ -6643,6 +6652,15 @@
"utila": "~0.4" "utila": "~0.4"
} }
}, },
"node_modules/dom-helpers": {
"version": "5.2.1",
"resolved": "https://registry.npmmirror.com/dom-helpers/-/dom-helpers-5.2.1.tgz",
"integrity": "sha512-nRCa7CK3VTrM2NmGkIy4cbK7IZlgBE/PYMn55rrXefr5xXDP0LdtfPnblFDoVdcAfslJ7or6iqAUnx0CCGIWQA==",
"dependencies": {
"@babel/runtime": "^7.8.7",
"csstype": "^3.0.2"
}
},
"node_modules/dom-serializer": { "node_modules/dom-serializer": {
"version": "1.4.1", "version": "1.4.1",
"resolved": "https://registry.npmmirror.com/dom-serializer/-/dom-serializer-1.4.1.tgz", "resolved": "https://registry.npmmirror.com/dom-serializer/-/dom-serializer-1.4.1.tgz",
@ -14075,6 +14093,11 @@
"resolved": "https://registry.npmmirror.com/react-is/-/react-is-17.0.2.tgz", "resolved": "https://registry.npmmirror.com/react-is/-/react-is-17.0.2.tgz",
"integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==" "integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w=="
}, },
"node_modules/react-lifecycles-compat": {
"version": "3.0.4",
"resolved": "https://registry.npmmirror.com/react-lifecycles-compat/-/react-lifecycles-compat-3.0.4.tgz",
"integrity": "sha512-fBASbA6LnOU9dOU2eW7aQ8xmYBSXUIWr+UmF9b1efZBazGNO+rcXT/icdKnYm2pTwcRylVUYwW7H1PHfLekVzA=="
},
"node_modules/react-refresh": { "node_modules/react-refresh": {
"version": "0.11.0", "version": "0.11.0",
"resolved": "https://registry.npmmirror.com/react-refresh/-/react-refresh-0.11.0.tgz", "resolved": "https://registry.npmmirror.com/react-refresh/-/react-refresh-0.11.0.tgz",
@ -14185,6 +14208,23 @@
} }
} }
}, },
"node_modules/react-virtualized": {
"version": "9.22.3",
"resolved": "https://registry.npmmirror.com/react-virtualized/-/react-virtualized-9.22.3.tgz",
"integrity": "sha512-MKovKMxWTcwPSxE1kK1HcheQTWfuCxAuBoSTf2gwyMM21NdX/PXUhnoP8Uc5dRKd+nKm8v41R36OellhdCpkrw==",
"dependencies": {
"@babel/runtime": "^7.7.2",
"clsx": "^1.0.4",
"dom-helpers": "^5.1.3",
"loose-envify": "^1.4.0",
"prop-types": "^15.7.2",
"react-lifecycles-compat": "^3.0.4"
},
"peerDependencies": {
"react": "^15.3.0 || ^16.0.0-alpha",
"react-dom": "^15.3.0 || ^16.0.0-alpha"
}
},
"node_modules/read-cache": { "node_modules/read-cache": {
"version": "1.0.0", "version": "1.0.0",
"resolved": "https://registry.npmmirror.com/read-cache/-/read-cache-1.0.0.tgz", "resolved": "https://registry.npmmirror.com/read-cache/-/read-cache-1.0.0.tgz",

View File

@ -13,6 +13,7 @@
"react-dom": "^18.2.0", "react-dom": "^18.2.0",
"react-router-dom": "^6.6.2", "react-router-dom": "^6.6.2",
"react-scripts": "5.0.1", "react-scripts": "5.0.1",
"react-virtualized": "^9.22.3",
"web-vitals": "^2.1.4" "web-vitals": "^2.1.4"
}, },
"scripts": { "scripts": {

View File

@ -1,26 +1,12 @@
import React ,{FC} from "react"; import React ,{FC} from "react";
import { NavBar, TabBar } from 'antd-mobile' import { TabBar } from 'antd-mobile'
import { import WidthUseNavigate from './../WidthUseNavigate/index'
Route,Routes,
useLocation,
MemoryRouter as Router,
useNavigate,
} from 'react-router-dom'
import { import {
AppOutline, AppOutline,
MessageOutline, MessageOutline,
UnorderedListOutline, UnorderedListOutline,
UserOutline, UserOutline,
} from 'antd-mobile-icons' } from 'antd-mobile-icons'
export default function Bottom (){
const navigate = useNavigate();
const location = useLocation()
const pathname = location
const setRouteActive = (value) => {
navigate(value)
}
const tabs = [ const tabs = [
{ {
key: '/home', key: '/home',
@ -48,13 +34,40 @@ export default function Bottom (){
}, },
] ]
return ( class BottomInner extends React.Component{
<TabBar activeKey={pathname} onChange={value => setRouteActive(value)}>
state = {
// 默认选中的TabBar菜单项
selectedTab: this.props.useLocation
}
// 组件接收到新的props此处实际上是路由信息就会触发该钩子函数
componentDidUpdate(prevProps) {
// prevProps 上一次的props此处也就是上一次的路由信息
// this.props 当前最新的props此处也就是最新的路由信息
// 注意:在该钩子函数中更新状态时,一定要在 条件判断 中进行,否则会造成递归更新的问题
if (prevProps.useLocation !== this.props.useLocation) {
// 此时,就说明路由发生切换了
this.setState({
selectedTab: this.props.useLocation
})
}
}
setRouteActive = (value) => {
this.props.to(value)
this.setState({
selectedTab: value
})
}
render() {
return <TabBar activeKey={this.state.selectedTab} onChange={value => this.setRouteActive(value)}>
{tabs.map(item => ( {tabs.map(item => (
<TabBar.Item key={item.key} icon={item.icon} title={item.title} badge= {item.badge}/> <TabBar.Item key={item.key} icon={item.icon} title={item.title} badge= {item.badge}/>
))} ))}
</TabBar> </TabBar>
) }
} }
@ -69,3 +82,7 @@ export default function Bottom (){
export function PersonalCenter() { export function PersonalCenter() {
return <div>我的</div> return <div>我的</div>
} }
// 使用高阶组件包裹当前类组件
const Bottom = WidthUseNavigate(BottomInner);
export default Bottom

View File

@ -0,0 +1,12 @@
.citylist{
height: 100%;
padding-top: 45px;
}
.citylist-navbar {
background: #f6f5f6;
margin-top: -45px;
}
ul{
list-style: none;
margin: 0;
}

View File

@ -1,7 +1,159 @@
import React from "react"; import React from "react";
import { NavBar, Space, Toast } from 'antd-mobile'
import { SearchOutline, MoreOutline, CloseOutline } from 'antd-mobile-icons'
import './index.css'
import axios from "axios";
import { getCurrentCity } from "../../utils";
import { List, AutoSizer } from "react-virtualized";
// list:[{},{}]
const formatCityIndex = (letter) => {
switch (letter) {
case '#':
return '当前城市'
case 'hot':
return '热门城市'
default:
return letter.toUpperCase()
}
}
const formatCityData = (list) => {
// {{'a':{},'b':{}}}
const cityList = {}
// 遍历
list.forEach(element => {
//获取短名称的第一个字母
const first = element.short.substr(0, 1)
//判断cityList中是否包含
if (cityList[first]) {
cityList[first].push(element)
} else {
cityList[first] = [element]
}
});
const cityIndex = Object.keys(cityList).sort()
return {
cityList,
cityIndex
}
}
// const right = (
// <div style={{ fontSize: 24 }}>
// <Space style={{ '--gap': '16px' }}>
// <SearchOutline />
// <MoreOutline />
// </Space>
// </div>
// )
const back = () => { }
// Toast.show({
// content: '点击了返回区域',
// duration: 1000,
// })
// const list =
// // [
// // 'Brian Vaughn',
// // // And so on...
// // ];
// Array(100).fill('Brian Vaughn')
// function rowRenderer({
// key, // Unique key within array of rows
// index, // Index of row within collection
// isScrolling, // The List is currently being scrolled
// isVisible, // This row is visible within the List (eg it is not an overscanned row)
// style, // Style object to be applied to row (to position it)
// }) {
// return (
// <div key={key} style={style}>
// {list[index]}
// </div>
// );
// }
export default class CityList extends React.Component { export default class CityList extends React.Component {
state = {
cityList: {},
cityIndex: [],
activeIndex: 0
}
componentDidMount() {
this.getCityList()
console.info("componentDidMount")
}
async getCityList() {
const res = await axios.get('http://localhost:8080/area/city?level=1')
const { cityList, cityIndex } = formatCityData(res.data.body)
// 热门城市数据
const hotRes = await axios.get('http://localhost:8080/area/hot')
cityList['hot'] = hotRes.data.body
// 放在第一位
cityIndex.unshift('hot')
const curCity = await getCurrentCity();
cityList['#'] = [curCity]
cityIndex.unshift('#')
console.info('shezhi zhuangtai')
this.setState({
cityList,
cityIndex
})
// this.setState(()=>{
// return {
// cityList:cityList,
// cityIndex:cityIndex
// }
// })
}
rowRenderer = ({
key, // Unique key within array of rows
index, // Index of row within collection
isScrolling, // The List is currently being scrolled
isVisible, // This row is visible within the List (eg it is not an overscanned row)
style, // Style object to be applied to row (to position it)
}) => {
const cityIndex = this.state.cityIndex
const letter = cityIndex[index]
return (
<div key={key} style={style} className="city">
<div className="title">{formatCityIndex(letter)}</div>
{
this.state.cityList[letter].map(item => (
<div className="name" key={item.value}>{item.label}</div>
))
}
</div>
);
}
getRowHeight = ({ index }) => {
return 36 + this.state.cityList[this.state.cityIndex[index]].length * 20
}
renderCityIndex() {
const { cityIndex, activeIndex } = this.state
return cityIndex.map((item, index) => {
<li className="city-index-item" key={item}>
<span className={activeIndex === index ? "index-active" : ''}>{item === 'hot' ? '热' : item.toUpperCase()}</span>
</li>
})
}
render() { render() {
return (<div>城市选择页面</div>) return <div className="citylist"><NavBar className="citylist-navbar" back='返回' onBack={back}>城市选择</NavBar>
<AutoSizer>
{({ width, height }) => (
<List
width={width}
height={height}
rowCount={this.state.cityIndex.length}
rowHeight={this.getRowHeight}
rowRenderer={this.rowRenderer}
/>
)}
</AutoSizer>
<ul className="city-index">{this.renderCityIndex()}</ul>
</div>
} }
} }

View File

@ -2,6 +2,7 @@ import React from 'react'
import Bottom from './../Bottom/index' import Bottom from './../Bottom/index'
import './index.css' import './index.css'
import { Outlet } from 'react-router-dom' import { Outlet } from 'react-router-dom'
import WidthUseNavigate from '../WidthUseNavigate'
export default class Home extends React.Component { export default class Home extends React.Component {
render() { render() {
return ( return (

13
src/pages/Index/index.css Normal file
View File

@ -0,0 +1,13 @@
.home {
padding-bottom: 50px;
}
.home .iconfont {
font-size: 20px;
}
.home .am-tab-bar-bar {
position: fixed;
bottom: 0;
}

View File

@ -7,21 +7,19 @@ import ImgZZ from './../../assets/images/nav-1.png'
import ImgHZ from './../../assets/images/nav-2.png' import ImgHZ from './../../assets/images/nav-2.png'
import ImgDTZF from './../../assets/images/nav-3.png' import ImgDTZF from './../../assets/images/nav-3.png'
import ImgQCZ from './../../assets/images/nav-4.png' import ImgQCZ from './../../assets/images/nav-4.png'
import './index.css'
const localCatalog = [ const localCatalog = [
{ "imgSrc": ImgZZ, "title": "整租", "path": "/todo" }, { "imgSrc": ImgZZ, "title": "整租", "path": "/todo" },
{ "imgSrc": ImgHZ, "title": "合租", "path": "/todo" }, { "imgSrc": ImgHZ, "title": "合租", "path": "/todo" },
{ "imgSrc": ImgDTZF, "title": "地图找房", "path": "/map" }, { "imgSrc": ImgDTZF, "title": "地图找房", "path": "/map" },
{ "imgSrc": ImgQCZ, "title": "去出租", "path": "/me" } { "imgSrc": ImgQCZ, "title": "去出租", "path": "/me" }
] ]
navigator.geolocation.getCurrentPosition(position=>{
console.log("当前位置信息",position)
})
class IndexInner extends React.Component { class IndexInner extends React.Component {
state = { state = {
swipers: [], swipers: [],
isSwiperLoaded: false, isSwiperLoaded: false,
groups: [] groups: [],
curCityName:''
} }
// 获取轮播图 // 获取轮播图
async getSwitpers() { async getSwitpers() {
@ -53,6 +51,14 @@ class IndexInner extends React.Component {
componentDidMount() { componentDidMount() {
this.getSwitpers() this.getSwitpers()
this.getGroups() this.getGroups()
const curCity = new window.BMapGL.LocalCity()
curCity.get(async res=>{
this.setState(()=>{
return {curCityName:res.name}
})
const result = await axios.get('http://localhost:8080/area/info?name=${res.name}')
console.log(result)
})
} }
renderSwipers() { renderSwipers() {
@ -69,9 +75,38 @@ class IndexInner extends React.Component {
{/* 轮播图 */} {/* 轮播图 */}
<div className='context-swapper'> <div className='context-swapper'>
<div>
{ {
this.state.isSwiperLoaded ? <Swiper autoplay loop autoplayInterval='1500'>{this.renderSwipers()}</Swiper> : "" this.state.isSwiperLoaded ? <Swiper autoplay loop autoplayInterval='1500'>{this.renderSwipers()}</Swiper> : ""
} }
</div>
<div className="search-box">
{/* 左侧白色区域 */}
<div className="search">
{/* 位置 */}
<div
className="location"
onClick={() => this.props.to('/citylist')}
>
<span className="name">{this.state.curCityName}</span>
<i className="iconfont icon-arrow" />
</div>
{/* 搜索表单 */}
<div
className="form"
onClick={() => this.props.to('/search')}
>
<i className="iconfont icon-seach" />
<span className="text">请输入小区或地址</span>
</div>
</div>
{/* 右侧地图图标 */}
<i
className="iconfont icon-map"
onClick={() => this.props.history.push('/map')}
/>
</div>
</div> </div>
{/* 本地导航 */} {/* 本地导航 */}

View File

@ -1,5 +1,6 @@
import React from "react"; import React from "react";
import './index.css' import './index.css'
import 'react-virtualized/styles.css'
export default class Map extends React.Component { export default class Map extends React.Component {
componentDidMount() { componentDidMount() {

24
src/utils/index.js Normal file
View File

@ -0,0 +1,24 @@
import axios from "axios"
export const getCurrentCity=()=>{
const localCity = JSON.parse(localStorage.getItem('local_city'))
if(!localCity){
return new Promise((resolve,reject)=>{
const curCity = new window.BMapGL.LocalCity()
curCity.get(async res=>{
try{
const result = await axios.get('http://localhost:8080/area/info?name=${res.name}')
localStorage.setItem('local_city',JSON.stringify(result.data.body))
resolve(result.data.body)
}catch(e){
reject(e)
}
})
})
}
// return new Promise((resolve)=>{
// return resolve(localCity)
// })
return Promise.resolve(localCity)
}