目录
- 1.业务需求
- 2.最初实现及出现的问题
- 3.解决 - `1000` 个标点时页面就出现 `卡顿` 问题
- 4.使用海量点、聚合标点后还有卡顿,排查其他原因
- 5.最终解决
- 5.1页面中list数据渲染问题解决
- 5.2地图相关实例不要放在 vue 的可响应数据中
- 页面展示
1.业务需求
需要在
高德地图
中标点,标点数量可能上万个
2.最初实现及出现的问题
- 【最初实现】使用高德地图的
Marker
标点Marker 实现标点代码
// 遍历list数据一个一个标点 let warnning = new AMap.Marker({ zIndex: type === 'alarm' ? 14 : 12, icon: icon, position: [item.longitude, item.latitude], anchor: 'bottom-center', extData: { tabType: type, ...item } }) this.markerList.push(warnning) // 用于 warnning.on('click', this.markerClick) // warnning.emit('click', { target: warnning });// map.add(warnning)
- 【问题】
1000
个标点时页面就出现卡顿
3.解决 - 1000
个标点时页面就出现 卡顿
问题
想尽各种办法:
- 【海量点第一种方法】:
海量点 MassMarks
官方示例 (代码示例如下)- 【海量点第二种方法】:
标注和标注图层-海量点
官方示例- 【点聚合】:
MarkerCluster
官方示例
【海量点第一种方法】代码
<script>
/* 注释掉的代码与当前功能无关 */
let map = null
// let infoWindowCon = null
// let contextMenu = null
let makerPeak = null
export default {
name: 'mapManager',
data() {
return {
// ...
dangerSucMass: null // 【关键代码】海量点图层
}
},
methods: {
// 使用【海量点第一种方法】实现标点
completeAddMarker(data) {
this.dangerSucMass?.clear()
const list = (data || []).map((item, index) => {
return {
id: item.id,
name: item.address,
lnglat: [item.longitude, item.latitude],
style: 0,
extData: {
tabType: 'dangerSuceess',
...item
}
}
})
this.dangerSucMass = new AMap.MassMarks(list, {
opacity: 0.8,
zIndex: 111,
cursor: 'pointer',
style: [{
url: require('@/assets/image/green.png'),
anchor: AMap.Pixel(0, 0),
size: new AMap.Size(10, 10),
zIndex: 3
}]
})
this.dangerSucMass.setMap(map)
this.dangerSucMass.on('click', this.successMarkerClick)
},
// 展示/隐藏图标
isShowSucMass(e) {
if (e) {
this.dangerSucMass.show()
this.markerTip.open(map)
} else {
this.dangerSucMass.hide()
this.markerTip.close()
}
},
//监听
successMarkerClick(e) {
console.log('e--successMarkerClick--打印', e)
// 添加点击marker时的提示
if (this.markerTip) {
this.markerTip.close() // 关闭提示
}
const data = e.data.extData
console.log('e.data.extData----打印', data)
this.infoWindowData = { ...data, type: 'dangerSuceess' }
const position = [data.longitude, data.latitude]
map.setCenter(new AMap.LngLat(position[0], position[1]), true)
this.markerTip = new AMap.InfoWindow({ // 提示插件
position: new AMap.LngLat(position[0], position[1]), // 经纬度
content: this.$refs['infoW'].$el,
offset: new AMap.Pixel(5, 0) // 偏移位置
})
this.markerTip.open(map)
// this.$refs.infoW.open({...e.data.extData, typeTab: 'dangerSuceess'})
},
}
}
</script>
4.使用海量点、聚合标点后还有卡顿,排查其他原因
以上三种办法 - 页面还是卡顿 - 基于以上三种解决办法排查到以下多方面原因:
- 页面中有list数据
列表渲染
,数据过多,页面数据渲染过多也会导致页面卡顿
地图相关的变量
在data 中声明
(此处以【海量点第一种方法】为例)
- 以上
【海量点第一种方法】代码
中可以看到,海量点实例dangerSucMass
在data
中声明 ↓↓↓- 所有
地图相关的实例不要放在 vue 的可响应数据中
,响应数据会劫持属性
,地图的属性会被修改
,另外,劫持的属性可能和渲染有关
,那么会增加很多响应的计算
,会很卡; 参考别人遇到的类似的问题-官方解释
5.最终解决
5.1页面中list数据渲染问题解决
最初地图标点和list数据使用的是一套数据
【解决】
地图标点数据
、页面渲染数据
分成两套列表数据
- 地图标点数据:获取所有标点数据
- 页面渲染数据列表:改成分页获取数据,单次获取一部分数据
5.2地图相关实例不要放在 vue 的可响应数据中
最终解决办法【海量点第一种方法】代码
<script>
/* 注释掉的代码与当前功能无关 */
let map = null
// let infoWindowCon = null
// let contextMenu = null
let makerPeak = null
let dangerSucMass = null // 【关键代码】【解决代码】海量点实例 - 不在 data 中
export default {
name: 'mapManager',
data() {
return {
// ...
// dangerSucMass: null // 【关键代码】海量点实例
}
},
methods: {
// 使用【海量点第一种方法】实现标点
completeAddMarker(data) {
dangerSucMass?.clear()
const list = (data || []).map((item, index) => {
return {
id: item.id,
name: item.address,
lnglat: [item.longitude, item.latitude],
style: 0,
extData: {
tabType: 'dangerSuceess',
...item
}
}
})
dangerSucMass = new AMap.MassMarks(list, {
opacity: 0.8,
zIndex: 111,
cursor: 'pointer',
style: [{
url: require('@/assets/image/green.png'),
anchor: AMap.Pixel(0, 0),
size: new AMap.Size(10, 10),
zIndex: 3
}]
})
dangerSucMass.setMap(map)
dangerSucMass.on('click', this.successMarkerClick)
},
// 展示/隐藏图标
isShowSucMass(e) {
if (e) {
dangerSucMass.show()
this.markerTip.open(map)
} else {
dangerSucMass.hide()
this.markerTip.close()
}
},
//监听
successMarkerClick(e) {
console.log('e--successMarkerClick--打印', e)
// 添加点击marker时的提示
if (this.markerTip) {
this.markerTip.close() // 关闭提示
}
const data = e.data.extData
console.log('e.data.extData----打印', data)
this.infoWindowData = { ...data, type: 'dangerSuceess' }
const position = [data.longitude, data.latitude]
map.setCenter(new AMap.LngLat(position[0], position[1]), true)
this.markerTip = new AMap.InfoWindow({ // 提示插件
position: new AMap.LngLat(position[0], position[1]), // 经纬度
content: this.$refs['infoW'].$el,
offset: new AMap.Pixel(5, 0) // 偏移位置
})
this.markerTip.open(map)
// this.$refs.infoW.open({...e.data.extData, typeTab: 'dangerSuceess'})
},
}
}
</script>