地圖找房模塊
功能:
- 展示當(dāng)前定位城市
- 展示該城市所有區(qū)的房源數(shù)據(jù)
- 展示某區(qū)下所有鎮(zhèn)的房源數(shù)據(jù)
- 展示某鎮(zhèn)下所有小區(qū)的房源數(shù)據(jù)
- 展示某小區(qū)下的房源數(shù)據(jù)列表
涉及到的功能點(diǎn):地圖標(biāo)注姑躲、縮放登記晋被、縮放事件等
1搬味,封裝頂部導(dǎo)航欄
1燕偶,在components中創(chuàng)建NavHeader組件封裝導(dǎo)航欄可復(fù)用組件
2燥透,使用NavHeader組件
export default function NavHeader ({children, history}) {
// history是props.history
// 默認(rèn)情況下栗弟,只有路由 Route 直接渲染的組件才能獲取到路由信息(比如:history.go()等)悍手,如果需要在其他組件中獲取到路由信息可以通過 withRouter 高階組件來獲取渴逻。
// 那么我們可以使用高階組件處理
// 1妙啃,從 react-router-dom 中導(dǎo)入 withRouter 高階組件
// 2档泽,使用 withRouter 包裹 NavHeader 組件
// 3,從 props 中解構(gòu)出 history 對象
// 4揖赴,調(diào)用 history.go() 實(shí)現(xiàn)返回上一頁
// 5馆匿,從 props 中解構(gòu)出 onLeftClick 函數(shù),實(shí)現(xiàn)自定義返回按鈕的點(diǎn)擊事件
import { withRouter } from 'react-router-dom'
export default function NavHeader ({children, history, onLeftClick}) {
const defaultHandler = () => history.go(-1)
return (
<NavBar
mode="light"
icon={<i className="iconfont icon-back"/>}
onLeftClick={onLeftClick || defaultHandler}
>
{children}
</NavBar>
)
}
以上代碼修改為:
function NavHeader ({children, history, onLeftClick}) {
const defaultHandler = () => history.go(-1) // 默認(rèn)點(diǎn)擊行為
return (
<NavBar
mode="light"
icon={<i className="iconfont icon-back"/>}
onLeftClick={onLeftClick || defaultHandler}
>
{children}
</NavBar>
)
}
export default withRouter(NavHeader)
}
onLeftClick點(diǎn)擊事件燥滑,可以在使用 NavHeader 組件自定義onLeftClick事件:
// Map組件
<NavHeader onLeftClick={() => {
this.props.history.go(-1)
}}>
地圖找房
</NavHeader>
添加props校驗(yàn):
- 1渐北,安裝:yarn add prop-types
- 2, 導(dǎo)入 PropTypes
import PropTypes from 'prop-types'
- 3, 給 NavHeader 組件的 children 和 onLeftClick 屬性添加 props 校驗(yàn)
function NavHeader ({children, history, onLeftClick}) {
const defaultHandler = () => history.go(-1)
return (
<NavBar
mode="light"
icon={<i className="iconfont icon-back"/>}
onLeftClick={onLeftClick || defaultHandler}
>
{children}
</NavBar>
)
}
NavHeader.propTypes = {
children: PropTypes.string.isRequired,
onLeftClick: PropTypes.func
}
export default withRouter(NavHeader)
組件間樣式覆蓋問題
css IN JS
- css IN JS:是使用 js 編寫 css 的統(tǒng)稱,用來解決 css 樣式?jīng)_突铭拧、覆蓋等問題
- css in js的具體實(shí)現(xiàn)有50多種赃蛛,比如:CSS Modules、styled-components等
- 推薦使用: CSS Modules(React腳手架已集成羽历,可直接使用)
CSS Modules:
- CSS Modules通過對css類名重命名焊虏,保證每個(gè)類名的唯一性,從而避免樣式?jīng)_突的問題
- 換句話:所有類名都具有“局部作用域”秕磷,只在當(dāng)前組件內(nèi)部生效
- 命名采用:BEM
BEM(Block塊诵闭,Element元素,Modifier三部分組成)命名規(guī)范澎嚣,比如: .list_item__active
- 在React腳手架中演化為:文件名疏尿、類名、hash(隨機(jī))三部分易桃,只需要指定類名即可
// 自動(dòng)生成的類名褥琐,我們只需要提供 classname即可
[filename]_[classname]__[hash]
// 類名
.error{}
// 生成的類名:
.Button_error__ax7yz
CSS Modules在項(xiàng)目中的使用:
1,創(chuàng)建名為[name].module.css的樣式文件(React腳手架中的約定晤郑,與普通CSS作區(qū)分)
在CityList組件中創(chuàng)建的樣式文件名:
index.module.css
2,組件中導(dǎo)入樣式文件
import styles from './index.module.css'
3敌呈,通過 styles 對象訪問對象中的樣式名來設(shè)置樣式
<div className={styles.test}></div>
示例:
image
CityList index.js:
import styles from './index.module.css'
<div className={styles.test}>測試樣式</div>
index.module.css:
.test {
color: red;
font-size: 40px;
}
- 對于組件庫中已經(jīng)有的全局樣式(比如:.am-navnar-title)贸宏,需要使用 :global() 來指定:
:global(.am-navnar-title){}
2, 根據(jù)定位展示當(dāng)前城市
- 1,獲取當(dāng)前定位城市
- 2磕洪,獲取地址解析器解析當(dāng)前城市坐標(biāo)
- 3吭练,調(diào)用 centerAndZoom()方法在地圖中展示當(dāng)前城市,并設(shè)置縮放級別為11
- 4析显,在地圖中添加比例尺和平移縮放控件
componentDidMount() {
// 獲取當(dāng)前定位城市
const {label, value} = JSON.parse(localStorage.getItem('current_city'))
//創(chuàng)建地址解析器實(shí)例
const map = new BMapGL.Map('container')
const myGeo = new BMapGL.Geocoder();
// 將地址解析結(jié)果顯示在地圖上鲫咽,并調(diào)整地圖視野
myGeo.getPoint(label, (point) => {
if(point){
map.centerAndZoom(point, 11);
map.addOverlay(new BMapGL.Marker(point, {title: label}))
// 添加比例尺和平移縮放控件
// 使用Map.addControl()方法向地圖添加控件
map.addControl(new BMapGL.ScaleControl)
map.addControl(new BMapGL.ZoomControl)
}else{
alert('您選擇的地址沒有解析到結(jié)果!');
}
}, label)
}
3谷异,創(chuàng)建文本覆蓋物
- 1, 創(chuàng)建label實(shí)例對象
- 2分尸,調(diào)用 setStyle()方法設(shè)置樣式
- 3,在 map 對象上調(diào)用 addOverlay()方法歹嘹,將文本覆蓋物添加到地圖中
const opts = {
position : point, // 指定文本標(biāo)注所在的地理位置
offset : new BMap.Size(30, -30) //設(shè)置文本偏移量
}
const label = new BMapGL.Label("文本信息", opts); // 創(chuàng)建文本標(biāo)注對象
// 設(shè)置樣式
label.setStyle({
color : "red",
fontSize : "12px",
height : "20px",
lineHeight : "20px",
fontFamily:"微軟雅黑"
});
// 將創(chuàng)建好的文本標(biāo)注添加為地圖的覆蓋物
map.addOverlay(label);
繪制房源覆蓋物
- 1箩绍,調(diào)用Label的setContent()方法,傳入HTML結(jié)構(gòu)荞下,修改HTML內(nèi)容的樣式
// 設(shè)置房源覆蓋物
Label.setContent(`
<div class="${styles.bubble}">
<p class="${styles.name}">哈哈哈</p>
<p>99套</p>
</div>
`)
- 2伶选,調(diào)用setStyle()修改覆蓋物樣式
Label.setStyle()
- 3, 給文本覆蓋物添加單擊事件
Label.addEventListener("click", () => {
console.log('被點(diǎn)擊了')
})
地圖找房
- 1,獲取房源數(shù)據(jù)尖昏,渲染覆蓋物
- 2,單擊覆蓋物后:1构资,放大地圖 2抽诉,獲取數(shù)據(jù),渲染下一級覆蓋物
1吐绵,渲染多有區(qū)的房源覆蓋物
- 1迹淌,獲取房源數(shù)據(jù)
- 2,遍歷數(shù)據(jù)己单,創(chuàng)建覆蓋物唉窃,給每個(gè)覆蓋物添加唯一標(biāo)識
- 3,給覆蓋物添加單擊事件
- 4纹笼,在單擊事件中纹份,獲取到當(dāng)前單擊項(xiàng)的唯一標(biāo)識
- 5,放大地圖(級別為13)廷痘,調(diào)用clearOverlays()方法清除當(dāng)前覆蓋物
myGeo.getPoint(label, async (point) => {
if(point){
map.centerAndZoom(point, 11);
map.addOverlay(new BMapGL.Marker(point, {title: label}))
map.addControl(new BMapGL.ScaleControl)
map.addControl(new BMapGL.ZoomControl)
// 獲取房源數(shù)據(jù)
const res = await axios.get(`http://localhost:8080/area/map?id=${value}`)
res.data.body.forEach(item => {
const {coord: {latitude, longitude}, label: areaname, count, value} = item
const areaPoint = new BMapGL.Point(longitude, latitude)
const opts = {
position: areaPoint, // 指定文本標(biāo)注所在的地理位置
offset: new BMapGL.Size(-35, -35) //設(shè)置文本偏移量
}
const Label = new BMapGL.Label("", opts)
// 給 label對象添加一個(gè)唯一標(biāo)識
Label.id = value
// 設(shè)置房源覆蓋物
Label.setContent(`
<div class="${styles.bubble}">
<p class="${styles.name}">${areaname}</p>
<p>${count}套</p>
</div>
`)
Label.setStyle(labelStyle);
map.addOverlay(Label);
// 添加單擊事件
Label.addEventListener("click", () => {
// 放大地圖蔓涧,以當(dāng)前點(diǎn)擊的覆蓋物為中心放大地圖
map.centerAndZoom(areaPoint, 13);
// 清除當(dāng)前覆蓋物信息
map.clearOverlays()
})
});
}else{
alert('您選擇的地址沒有解析到結(jié)果!');
}
}, label)