如下內容轉載自前端develop的文章《騰訊地圖實現地圖找房功能》做者:前端developjavascript
連接:https://juejin.im/post/684490...html
來源:掘金前端
著做權歸做者全部。商業轉載請聯繫做者得到受權,非商業轉載請註明出處。java
地圖找房功能使用點聚合來實現的。官網示例以下:https://lbs.qq.com/javascript...git
鏈家的地圖找房主要分爲三層。第一層爲市區層,好比南山、羅湖等;第二層爲片區,好比南頭、科技園等;第三層則爲小區。github
由於第一層,第二層的數據沒有那麼多,這兩個接口都是把全部的數據一次返回給前端。可是第三層的數據量就很是的巨大了,鏈家採起的是返回部分數據,將前端頁面上顯示的最大經緯度以及最小經緯度傳給後臺,後臺再將篩選後的數據返回給前端。(接口地址你們可使用 Chrome 的開發工具進行抓包,這裏須要注意的是鏈家的接口採用 jsonp 的形式,因此須要抓取 JS)web
首先須要添加騰訊地圖的API,這裏推薦使用異步加載的方式。由於項目使用 Vue 進行開發的單頁應用,有可能用戶並無進入地圖找房的頁面,因此這裏建議在打開地圖找房的頁面時添加騰訊地圖的API。json
異步加載須要避免一個重複加載的問題,即無論用戶是第幾回打開地圖找房,地圖的 API 都是同一個。 這裏爲了下降代碼複雜度,沒有使用單例模式,具體的代碼以下:api
const TXMap = { map: undefined, // 地圖實例 // 異步加載獲取api getApi (funName) { let script = document.createElement('script') script.type = 'text/javascript' script.src = `http://map.qq.com/api/js?v=2.exp&callback=${funName}` document.body.appendChild(script) } }
能夠看到異步加載就是動態加入 script 標籤,src 爲騰訊地圖 api 的地址,src 包含一個 callback 參數,表示 js 加載完畢後會調用 funName 這個函數。添加了地圖 api 以後,window 對象會有一個 qq.maps 對象,咱們能夠用來判斷是否已經添加了 api,來避免重複添加 api。app
接下來就是實現自定義覆蓋物這個方法了。仍是參照官方文檔:https://lbs.qq.com/javascript...
const TXMap = { map: undefined, overlays: [], // 存放全部覆蓋物 sourceData: [], // 原始數據 listener: undefined, // 地圖縮放或平移的事件監聽器 getApi () {}, /* 前面已經聲明,此處省略 */ // 實現自定義覆蓋物 drawOverlay (options) { let _this = this // 下面有多個 window 對象的方法,避免 this 的指向問題 this.sourceData = options.data // 存放原始數據 // 繪製覆蓋物以前,清理以前繪製的覆蓋物 this.clearOverlays() // 若是 initMap 方法已經實現,那麼咱們能夠直接調用,不然須要進行定義 if (window.initMap === undefined) { window.initMap = function () {} // 繪製覆蓋物的具體實現 // 地圖 api 若是沒有引入則調用 getApi 方法,不然直接調用 initMap () window.qq === undefined ? this.getApi('initMap') : window.initMap() } else { window.initMap() } }, // 清除自定義覆蓋物 clearOverlays () { let overlay while (overlay = this.overlays.pop()) { overlay.onclick = null // 移除點擊事件 overlay.parentNode.removeChild(overlay) // 移除 dom 元素 } }, // 在 Vue 組件的 beforeDestroy 調用,重置地圖,移除時間爲監聽,避免內存泄漏 clearMap () { this.map = undefined if (this.listener) { window.qq.maps.event.removeListener(this.listener) } } }
這個地圖找房的架子到此就搭得差很少了,接下來就看看繪製覆蓋物的具體實現了,也就是 initMap 這個方法。
window.initMap = function () { if (_this.map === undefined) { // 地圖對象爲undefined時, 須要進行地圖的繪製 _this.map = new window.qq.maps.Map(document.getElementById(options.containerId), { // 初始化地圖中心 center: new window.qq.maps.LatLng(options.lat || 22.702, options.lng || 114.09), // 初始化縮放級別 zoom: options.zoom || 10, // 地圖最小縮放級別 minZoom: 10, // 停用縮放控件 zoomControl: false, // 停用地圖類型控件 mapTypeControl: false }) // idle 事件, 地圖縮放或平移以後觸發該事件 _this.listener = window.qq.maps.event.addListener(_this.map, 'idle', () => { // 獲取當前地圖可視範圍的最大最小經緯度 let bounds = _this.map.getBounds() // 獲取當前地圖的縮放級別 let zoom = _this.map.getZoom() // 調用 Vue 組件對 idle 事件的處理函數 options.callback && options.callback(bounds, zoom) }) } // 自定義覆蓋物 if (window.CustomOverlay === undefined) { window.CustomOverlay = function (lat, lng, name, houseCount) { // 調用地圖 api 計算出覆蓋物的位置 this.position = new window.qq.maps.LatLng(lat, lng) this.name = name // 區域名 this.houseCount = houseCount // 房源數量 } // 繼承 Overlay window.CustomOverlay.prototype = new window.qq.maps.Overlay() // 自定義覆蓋物構造函數,定義覆蓋爲的 DOM 結構,DOM 結構,樣式你們能夠根據需求本身繪製 window.CustomOverlay.prototype.construct = function () { let div = this.div = document.createElement('div') div.className = 'my-overlay' // 覆蓋物類名 // 覆蓋物 html 結構 this.div.innerHTML = `<p class="count" >${this.houseCount}<span>套</span></p><p class="name">${this.name}</p>` //將dom添加到覆蓋物層,overlayMouseTarget的順序容器 5,此容器包含透明的鼠標相應元素,用於接收Marker的鼠標事件 this.getPanes().overlayMouseTarget.appendChild(div) // 將 div 添加到 overlays,能夠用之後續處理 _this.overlays.push(div) // 定義覆蓋物的點擊事件 let center = this.position this.div.onclick = function () { // 點擊以後對地圖進行縮放以及平移 let zoom = _this.map.getZoom() if (zoom < 13) { _this.map.setCenter(center) _this.map.setZoom(13) } else if (zoom >= 13 && zoom < 15) { _this.map.setCenter(center) _this.map.setZoom(15) } } } // 實現 draw 接口來繪製 DOM 元素 window.CustomOverlay.prototype.draw = function () { let overlayProjection = this.getProjection() // 獲取覆蓋物容器的相對像素座標 let pixel = overlayProjection.fromLatLngToDivPixel(this.position) let divStyle = this.div.style // 根據 DOM 元素調整定位的位置 divStyle.top = pixel.y - 53 + 'px' divStyle.left = pixel.x - 30 + 'px' } } // 根據接口數據繪製覆蓋物 if (_this.sourceData.length > 0) { _this.sourceData.map(item => { let customOverlay = new window.CustomOverlay(item.latitude, item.longitude, item.name, item.house_count) customOverlay.setMap(_this.map) }) } }
至此,地圖找房對繪製覆蓋物方法的封裝就完成了,接下來只須要將 TXMap 暴露出去,而後在 Vue 組件中進行引入,以後再向下面的方法使用便可
TXMap.drawOverlay({ containerId: 'map-box', data: res.data })
這個例子用了鏈家的數據作了兩層,你們能夠根據本身的須要進行修改。
項目地址: GitHub
本文實現地圖找房功能使用的是咱們2D版JSAPI,目前咱們已經上線3D版地圖API-JavaScript API GL。