diff --git a/package-lock.json b/package-lock.json index 568ea6b..f685bc9 100644 --- a/package-lock.json +++ b/package-lock.json @@ -18,6 +18,7 @@ "react-dom": "^18.2.0", "react-router-dom": "^6.6.2", "react-scripts": "5.0.1", + "react-virtualized": "^9.22.3", "web-vitals": "^2.1.4" } }, @@ -5743,6 +5744,14 @@ "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": { "version": "4.6.0", "resolved": "https://registry.npmmirror.com/co/-/co-4.6.0.tgz", @@ -6643,6 +6652,15 @@ "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": { "version": "1.4.1", "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", "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": { "version": "0.11.0", "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": { "version": "1.0.0", "resolved": "https://registry.npmmirror.com/read-cache/-/read-cache-1.0.0.tgz", diff --git a/package.json b/package.json index 4cea583..e076239 100644 --- a/package.json +++ b/package.json @@ -13,6 +13,7 @@ "react-dom": "^18.2.0", "react-router-dom": "^6.6.2", "react-scripts": "5.0.1", + "react-virtualized": "^9.22.3", "web-vitals": "^2.1.4" }, "scripts": { diff --git a/src/pages/Bottom/index.js b/src/pages/Bottom/index.js index 915dbe6..b18c520 100644 --- a/src/pages/Bottom/index.js +++ b/src/pages/Bottom/index.js @@ -1,60 +1,73 @@ import React ,{FC} from "react"; -import { NavBar, TabBar } from 'antd-mobile' -import { - Route,Routes, - useLocation, - MemoryRouter as Router, - useNavigate, -} from 'react-router-dom' +import { TabBar } from 'antd-mobile' +import WidthUseNavigate from './../WidthUseNavigate/index' import { AppOutline, MessageOutline, UnorderedListOutline, UserOutline, } from 'antd-mobile-icons' -export default function Bottom (){ - const navigate = useNavigate(); - const location = useLocation() - const pathname = location - - const setRouteActive = (value) => { - navigate(value) +const tabs = [ + { + key: '/home', + title: '首页', + icon: , + badge: '1', + }, + { + key: '/home/todo', + title: '待办', + icon: , + badge: '2', + }, + { + key: '/home/message', + title: '消息', + icon: , + badge: '3', + }, + { + key: '/home/me', + title: '我的', + icon: , + badge: '4', + }, +] + +class BottomInner extends React.Component{ + + state = { + // 默认选中的TabBar菜单项 + selectedTab: this.props.useLocation } - - const tabs = [ - { - key: '/home', - title: '首页', - icon: , - badge: '1', - }, - { - key: '/home/todo', - title: '待办', - icon: , - badge: '2', - }, - { - key: '/home/message', - title: '消息', - icon: , - badge: '3', - }, - { - key: '/home/me', - title: '我的', - icon: , - badge: '4', - }, - ] - - return ( - setRouteActive(value)}> + + // 组件接收到新的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 this.setRouteActive(value)}> {tabs.map(item => ( ))} - ) + } } @@ -68,4 +81,8 @@ export default function Bottom (){ export function PersonalCenter() { return
我的
- } \ No newline at end of file + } + +// 使用高阶组件包裹当前类组件 +const Bottom = WidthUseNavigate(BottomInner); +export default Bottom \ No newline at end of file diff --git a/src/pages/CityList/index.css b/src/pages/CityList/index.css new file mode 100644 index 0000000..4fe60d7 --- /dev/null +++ b/src/pages/CityList/index.css @@ -0,0 +1,12 @@ +.citylist{ + height: 100%; + padding-top: 45px; +} +.citylist-navbar { + background: #f6f5f6; + margin-top: -45px; +} +ul{ + list-style: none; + margin: 0; +} diff --git a/src/pages/CityList/index.js b/src/pages/CityList/index.js index d313f17..c7d1a3a 100644 --- a/src/pages/CityList/index.js +++ b/src/pages/CityList/index.js @@ -1,7 +1,159 @@ 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 + } +} -export default class CityList extends React.Component{ - render(){ - return (
城市选择页面
) +// const right = ( +//
+// +// +// +// +//
+// ) + +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 ( +//
+// {list[index]} +//
+// ); +// } +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 ( +
+
{formatCityIndex(letter)}
+ { + this.state.cityList[letter].map(item => ( +
{item.label}
+ )) + } +
+ ); + } + getRowHeight = ({ index }) => { + return 36 + this.state.cityList[this.state.cityIndex[index]].length * 20 + } + + renderCityIndex() { + const { cityIndex, activeIndex } = this.state + return cityIndex.map((item, index) => { +
  • + {item === 'hot' ? '热' : item.toUpperCase()} +
  • + }) + } + + render() { + return
    城市选择 + + {({ width, height }) => ( + + )} + +
      {this.renderCityIndex()}
    +
    } } \ No newline at end of file diff --git a/src/pages/Home/index.js b/src/pages/Home/index.js index c5175ce..501df81 100644 --- a/src/pages/Home/index.js +++ b/src/pages/Home/index.js @@ -2,10 +2,11 @@ import React from 'react' import Bottom from './../Bottom/index' import './index.css' import { Outlet } from 'react-router-dom' +import WidthUseNavigate from '../WidthUseNavigate' export default class Home extends React.Component { render() { return (
    ) } -} \ No newline at end of file +} diff --git a/src/pages/Index/index.css b/src/pages/Index/index.css new file mode 100644 index 0000000..383763a --- /dev/null +++ b/src/pages/Index/index.css @@ -0,0 +1,13 @@ +.home { + padding-bottom: 50px; + } + + .home .iconfont { + font-size: 20px; + } + + .home .am-tab-bar-bar { + position: fixed; + bottom: 0; + } + \ No newline at end of file diff --git a/src/pages/Index/index.js b/src/pages/Index/index.js index d9276eb..606a759 100644 --- a/src/pages/Index/index.js +++ b/src/pages/Index/index.js @@ -7,21 +7,19 @@ import ImgZZ from './../../assets/images/nav-1.png' import ImgHZ from './../../assets/images/nav-2.png' import ImgDTZF from './../../assets/images/nav-3.png' import ImgQCZ from './../../assets/images/nav-4.png' - +import './index.css' const localCatalog = [ { "imgSrc": ImgZZ, "title": "整租", "path": "/todo" }, { "imgSrc": ImgHZ, "title": "合租", "path": "/todo" }, { "imgSrc": ImgDTZF, "title": "地图找房", "path": "/map" }, { "imgSrc": ImgQCZ, "title": "去出租", "path": "/me" } ] -navigator.geolocation.getCurrentPosition(position=>{ - console.log("当前位置信息",position) -}) class IndexInner extends React.Component { state = { swipers: [], isSwiperLoaded: false, - groups: [] + groups: [], + curCityName:'' } // 获取轮播图 async getSwitpers() { @@ -53,6 +51,14 @@ class IndexInner extends React.Component { componentDidMount() { this.getSwitpers() 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() { @@ -69,9 +75,38 @@ class IndexInner extends React.Component { {/* 轮播图 */}
    +
    { this.state.isSwiperLoaded ? {this.renderSwipers()} : "" } +
    +
    + {/* 左侧白色区域 */} +
    + {/* 位置 */} +
    this.props.to('/citylist')} + > + {this.state.curCityName} + +
    + + {/* 搜索表单 */} +
    this.props.to('/search')} + > + + 请输入小区或地址 +
    +
    + {/* 右侧地图图标 */} + this.props.history.push('/map')} + /> +
    {/* 本地导航 */} diff --git a/src/pages/Map/index.js b/src/pages/Map/index.js index 88c2447..bad2125 100644 --- a/src/pages/Map/index.js +++ b/src/pages/Map/index.js @@ -1,5 +1,6 @@ import React from "react"; import './index.css' +import 'react-virtualized/styles.css' export default class Map extends React.Component { componentDidMount() { diff --git a/src/utils/index.js b/src/utils/index.js new file mode 100644 index 0000000..b00cc62 --- /dev/null +++ b/src/utils/index.js @@ -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) +} \ No newline at end of file