以下内容转载自前端develop的文章《腾讯地图实现地图找房性能》

作者:前端develop

链接:https://juejin.im/post/684490...

起源:掘金

著作权归作者所有。商业转载请分割作者取得受权,非商业转载请注明出处。

链家实现的成果

剖析

地图找房性能应用点聚合来实现的。官网示例如下:https://lbs.qq.com/javascript...

链家的地图找房次要分为三层。第一层为市区层,比方南山、罗湖等;第二层为片区,比方南头、科技园等;第三层则为小区。

因为第一层,第二层的数据没有那么多,这两个接口都是把所有的数据一次返回给前端。然而第三层的数据量就十分的微小了,链家采取的是返回局部数据,将前端页面上显示的最大经纬度以及最小经纬度传给后盾,后盾再将筛选后的数据返回给前端。(接口地址大家能够应用 Chrome 的开发工具进行抓包,这里须要留神的是链家的接口采纳 jsonp 的模式,所以须要抓取 JS)

实现

首先须要增加腾讯地图的API,这里举荐应用异步加载的形式。因为我的项目应用 Vue 进行开发的单页利用,有可能用户并没有进入地图找房的页面,所以这里倡议在关上地图找房的页面时增加腾讯地图的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。

接下来就是实现自定义覆盖物这个办法了。还是参照官网文档: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。

对应上文性能的3D版地图API文档链接:
点聚合、自定义覆盖物