前言
模仿南京体彩网点地图功能做一个demo
准备工作
1、参考博客以及相关地址
【Uniapp 附项目】腾讯地图的导入、定位、自定义标点与信息窗体、区域绘制的使用:文档地址
2、注册腾讯位置服务账号
我们需要先在腾讯位置服务注册一个账号,以申请获取 key 等权限信息。
腾讯位置服务:https://lbs.qq.com/
点击控制台后,点击应用管理创建新应用;
点击添加key,创建自己的key值,后面需要用到;
下面是最后生成的key:
导入以及使用
1、参考相关地址
腾讯地图官方文档:地址
2、导入地图
效果
代码
<template>
<view class="content">
<view class="wrapperBox">
<view id="wrapper"></view>
</view>
</view>
</template>
<script>
let mapObj = null // 生成地图实例
// ------------------------------ 更新内容1 ----------------------------- //
// 创建多个标点
let wangDian1 = [] // 生成图标实例1
let wangDian2 = [] // 生成图标实例2
let wangDian3 = [] // 生成图标实例3
let wangDian4 = [] // 生成图标实例4
let wangDian5 = [] // 生成图标实例5
let marker = [] // 生成标点实例
// ---------------------------------------------------------------------- //
let infoWindow = null // 自定义信息窗体
let isShowText = false // 窗体是否打开
window.mapInit = function () {
// 挂载地图实例
mapObj = new TMap.Map('wrapper', {
center: new TMap.LatLng(28.900484, 118.508882), // 地图初始坐标
zoom: 14, // 缩放等级
// mapStyleId: 'style1', // 地图样式
// baseMap: {
// //设置底图样式
// type: 'vector', //设置底图为矢量底图
// features: [
// //设置矢量底图要素类型
// 'base',
// 'point',
// ],
// },
zoomControl: false, // 设置是否启用缩放控件
})
infoWindow = new TMap.InfoWindow({
// 设置信息窗体
map: mapObj, // 挂载的地图实例
// enableCustom: false, // 是否自定义窗体
// position: new TMap.LatLng(28.900484, 118.508882), // 初始标点坐标
position: new TMap.LatLng(0, 0), // 初始标点坐标
offset: {
// 信息窗体的偏移量
y: -30,
x: 0,
},
// content: `<div style="width: 250px;height: 134px;padding:16px; background-color: white;"></div>`, // 必须设置一个底边的dom,否则会出现白边
})
mapObj.on('click', function (evt) {
// 地图全局事件
// mapObj.setCenter(
// new TMap.LatLng(evt.latLng.getLat().toFixed(6), evt.latLng.getLng().toFixed(6)),
// )
//设置infoWindow
if (isShowText) {
// 控制是否打开窗体
isShowText = true
} else {
infoWindow.close()
}
})
}
export default {
data() {
return {
key: 'XXXXX-XXXXX-XXXXX-XXXXX-XXXXX-XXXXX', //这里换成自己的key值
iconItem: [
{
// 模拟数据
name: 'wangDian1', // 样式类型
// src: require('@/static/dot-01.png'), // 图片路径
position: [28.900484, 118.508882], // 标点中心坐标
markerUrl: '/src/static/images/location1.png', // 标点图片样式
// markerList: [
// [
// 22.22839, 113.460787, 22.227644, 113.460801, 22.227582, 113.45945, 22.228346,
// 113.459423,
// ],
// ],
// fillColor: 'rgba(35, 181, 29, 0.6)',
// fillColorHover: 'rgba(35, 181, 29, 0.8)',
// strokeColor: 'rgba(35, 181, 29, 1)',
},
{
name: 'wangDian2',
// src: require('@/static/dot-02.png'),
position: [28.831234, 118.361211],
markerUrl: '/src/static/images/location1.png', // 标点图片样式
},
{
name: 'wangDian3',
// src: require('@/static/dot-03.png'),
position: [28.882022, 118.486322],
markerUrl: '/src/static/images/location2.png', // 标点图片样式
},
{
name: 'wangDian4',
// src: require('@/static/dot-04.png'),
position: [28.903053, 118.514926],
markerUrl: '/src/static/images/location1.png', // 标点图片样式
},
{
name: 'wangDian5',
// src: require('@/static/dot-04.png'),
position: [28.829513, 118.355959],
markerUrl: '/src/static/images/location2.png', // 标点图片样式
},
],
// ---------------------------------------------------------------------- //
}
},
onLoad() {
// #ifdef H5
this.loadScrpit()
// #endif
// ------------------------------ 更新内容3 ----------------------------- //
let time = setInterval(() => {
// 等待地图挂载
if (mapObj != null) {
clearInterval(time)
this.setIcon() // 挂载坐标图片信息
}
}, 100)
// ---------------------------------------------------------------------- //
},
created() {
// let that = this
// window.getParkDetail = function (res) {
// // 设置信息窗体触发事件
// if (res == 0) {
// that.isDetail1 = true
// }
// if (res == 2) {
// that.isDetail2 = true
// }
// }
},
methods: {
// 初始化
loadScrpit() {
// 挂载js
var script = document.createElement('script')
script.src = `https://map.qq.com/api/gljs?v=1.exp&key=${this.key}&libraries=visualization&callback=mapInit`
document.body.appendChild(script)
},
// ------------------------------ 更新内容4 ----------------------------- //
setIcon() {
// 创建标点图标
let that = this
// 创建 AMap.Icon 实例
wangDian1 = new TMap.MarkerStyle({
width: 35, // 定义宽,单位:PX
height: 40, // 定义高,单位:PX
src: that.iconItem[0].markerUrl, // 标点图片链接:本地图片
})
wangDian2 = new TMap.MarkerStyle({
width: 35,
height: 40,
src: that.iconItem[1].markerUrl,
})
wangDian3 = new TMap.MarkerStyle({
width: 35,
height: 40,
src: that.iconItem[2].markerUrl,
})
wangDian4 = new TMap.MarkerStyle({
width: 35,
height: 40,
src: that.iconItem[3].markerUrl,
})
wangDian5 = new TMap.MarkerStyle({
width: 35,
height: 40,
src: that.iconItem[4].markerUrl,
})
this.setMapMarker() // 调用创建标点
},
setMapMarker() {
// 创建标点实例
let geometries = []
for (let i = 0; i < this.iconItem.length; i++) {
let obj = {
// 点标记数据
id: i, //点标记唯一标识,后续如果有删除、修改位置等操作,都需要此id
styleId: this.iconItem[i].name, // 对应标点实例的style的名称
position: new TMap.LatLng(this.iconItem[i].position[0], this.iconItem[i].position[1]), // 标点的坐标
properties: {
// 自定义属性
title: this.iconItem[i].name,
},
}
geometries.push(obj)
}
marker = new TMap.MultiMarker({
// 构造函数创建标点实例
id: 'marker-layer', // 定义的ID名称
map: mapObj, // 挂载的地图实例
styles: {
// 加入标点的样式
wangDian1: wangDian1,
wangDian2: wangDian2,
wangDian3: wangDian3,
wangDian4: wangDian4,
wangDian5: wangDian5,
},
geometries: geometries, // 点标记数据数组
})
let that = this
marker.on('click', function (evt) {
// 给标点绑定事件打开信息窗体
that.setInfoWindow(evt)
})
},
// ---------------------------------------------------------------------- //
setInfoWindow(evt) {
// let that = this
// 信息窗体模拟数据,需要使用接口
// let imageIcon = require("@/static/icon-22.png");
let index = 0
let onSaleGame = ''
let assetNumber = ''
let address = ''
let phoneNumber = ''
//设置infoWindow
infoWindow.open() //打开信息窗
infoWindow.setPosition(evt.geometry.position) // 根据当前坐标设置信息窗位置
// console.log(evt.geometry.position);
// 设置点击后的地图偏移的中心点
mapObj.setCenter(new TMap.LatLng(evt.geometry.position.lat, evt.geometry.position.lng))
if (evt.geometry.properties.title == 'wangDian1') {
// 根据不同的类型设置标点信息,需要接口代替
index = 0
onSaleGame = '全游戏(含竞彩)'
assetNumber = '3308065001'
address = '天马镇胜利街1号'
phoneNumber = '13867013160'
}
if (evt.geometry.properties.title == 'wangDian2') {
// 根据不同的类型设置标点信息,需要接口代替
index = 1
onSaleGame = '全游戏(含竞彩)'
assetNumber = '3308065014'
address = '球川镇红旗岗'
phoneNumber = '15924099865'
}
if (evt.geometry.properties.title == 'wangDian3') {
// 根据不同的类型设置标点信息,需要接口代替
index = 2
onSaleGame = '全游戏(不含竞彩)'
assetNumber = '3308065018'
address = '金川街道新都东大道152号'
phoneNumber = '13735804999'
}
if (evt.geometry.properties.title == 'wangDian4') {
// 根据不同的类型设置标点信息,需要接口代替
index = 3
onSaleGame = '全游戏(含竞彩)'
assetNumber = '3308065020'
address = '天马镇法院街6号'
phoneNumber = '15869087056'
}
if (evt.geometry.properties.title == 'wangDian5') {
// 根据不同的类型设置标点信息,需要接口代替
index = 4
onSaleGame = '全游戏(不含竞彩)'
assetNumber = '3308065023'
address = '球川镇红旗岗红旗街6号'
phoneNumber = '15257031888'
}
// 设置信息窗体的样式,通过模板字符串赋值
infoWindow.setContent(`
<div>
<div style="display: flex;justify-content: space-between;flex-flow: column;height:120px;">
<img style="width: 30px; height: 30px;" src="/src/static/images/icon_ticai.jpg">
<span style="font-size: 24px; position: absolute; left: 44px; top: 23px;">中国体育彩票</span>
<div style="display: flex;align-items: center;justify-content: flex-start;width:220px;color:black;font-weight: bold;font-size: 15px;">
<div>网点:</div><div>${assetNumber}</div>
</div>
<div style="display: flex;align-items: center;justify-content: flex-start;width:220px;color:black;font-weight: 400;font-size: 15px;">
<div>在售游戏:</div><div>${onSaleGame}</div>
</div>
<div style="display: flex;align-items: center;justify-content: flex-start;width:245px;color:black;font-weight: 400;font-size: 15px;">
<div>门店地址:</div><div>${address}</div>
</div>
<div style="display: flex;align-items: center;justify-content: flex-start;width:220px;color:black;font-weight: 400;font-size: 12px;">
<div>联系电话:</div><div style="color: rgb(0, 0, 238)">${phoneNumber}</div> <img style="display: inline-block; width: 16px;" src="/src/static/images/icon_tel.png">
</div>
</div>
<hr style="margin-top:10px;">
<a class="tonav" href="https://apis.map.qq.com/uri/v1/routeplan?type=walk&to=体彩兼营店&tocoord=${evt.geometry.position}&policy=1&referer=OB4BZ-D4W3U-B7VVO-4PJWW-6TKDJ-WPB77"
style="display: block;
position: relative;
background-color: #0079ff;
top: 5px;
margin: auto;
font-size: 21px;
border-radius: 4px;
width: 79px;
height: 34px;
text-align: center;">
<img src="/src/static/images/to-here.png" style="position: absolute; height: 21px; left: 4px; top: 7px;">
<span style="display: block;
position: relative;
top: 6px;
left: 8px;
font-size: 17px;
color: #fff;">
去这里</span>
</a>
</div>`)
isShowText = true // 设置打开
},
},
}
</script>
<style lang="scss" scoped>
.content {
position: fixed;
top: 0;
left: 0;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
}
.wrapperBox {
position: relative;
width: 100vw;
height: 100vh;
z-index: 1;
}
#wrapper {
z-index: 20;
width: 120vw;
height: 120vh;
top: -10vh;
left: -10vw;
position: absolute;
}
</style>
3、代码讲解
挂载地图实例
在本文中我使用 mapObj 全局存储地图的实例,new TMap.Map('id',Object) 的参数:
id:地图将会渲染在同名 id 的 view 或 div 内。
Object:你可以通过该对象决定你的地图需要哪些图层与初始定位,还有缩放的级数等功能。
- center: new TMap.LatLng(22.254515, 113.469689) ,设置中心点的位置;
- zoom:初始地图的缩放级数,同样也是根据你的业务需求设置就好了;
设置地图中心点
腾讯地图提供了 setCenter() 方法可供设置中心点,
mapObj.setCenter(new TMap.LatLng(Latitude, Longitude))
自定义标点
自定义标点主要是定义图标的图像以及大小、图片地址等参数。
效果
代码
本地图创建了多个地图标点
// 创建多个标点
let wangDian1 = [] // 生成图标实例1
let wangDian2 = [] // 生成图标实例2
let wangDian3 = [] // 生成图标实例3
let wangDian4 = [] // 生成图标实例4
let wangDian5 = [] // 生成图标实例5
此处为后台模拟数据,仅供参考
iconItem: [{
// 模拟数据
name: 'wangDian1', // 样式类型
position: [28.900484, 118.508882], // 标点中心坐标
markerUrl: '/src/static/images/location1.png', // 标点图片样式
}]
在 onLoad() 里设置定时器监听地图是否挂载成功,没挂载地图实例前无法挂载标点图片与坐标标点。一旦监听到地图组件挂载便取消对应的定时器监听。
let time = setInterval(() => {
// 等待地图挂载
if (mapObj != null) {
clearInterval(time)
this.setIcon() // 挂载坐标图片信息
}
}, 100)
自定义信息窗体
实现信息框体功能,实际上就是为标点绑定一个点击事件,点击后再对相应的标点进行渲染。难点主要在如何渲染信息窗体数据并且在信息窗体内绑定点击事件。
创建全局的的实例 infoWindow ,也是只要挂载一次即可。主要用于信息窗体的打开与关闭。
isShowText 是用于判断当前的窗体是否打开,在点击或移动地图时关闭窗体。
let infoWindow = null // 自定义信息窗体
let isShowText = false // 窗体是否打开
infoWindow.open():每次点击标点时触发这个方法,打开信息窗体。
infoWindow.setPosition():根据当前坐标设置信息窗体位置,evt.geometry.position 就是携带过来的标点坐标。
mapObj.setCenter():这里有个需求就是点击信息标点后移动到屏幕的中心,所以使用了这个方法,如果你们的需求没有的话,不需要这个也是可以的。
//设置infoWindow
infoWindow.open() //打开信息窗
infoWindow.setPosition(evt.geometry.position) // 根据当前坐标设置信息窗位置
// console.log(evt.geometry.position);
// 设置点击后的地图偏移的中心点
mapObj.setCenter(new TMap.LatLng(evt.geometry.position.lat, evt.geometry.position.lng))
infoWindow:可以在地图后就挂载,且只用挂载一次,不同的信息窗体样式可以通过下文的 infoWindow.setContent() 方法重新定义。
- map:挂载的地图实例;
- enableCustom:如果用的是自定义的窗体一定需要开启;
- position:这个参数是必传的,不然无法显示信息窗体;
- offset:这个标点是相对于所点的标点坐标的偏移量,看需求是在哪个位置展示;
- content:必须设置一个底层的dom边框,否则会启用默认的样式,导致样式边框出现白边。而且通过infoWindow.setContent() 方法也无法消除。
infoWindow = new TMap.InfoWindow({
// 设置信息窗体
map: mapObj, // 挂载的地图实例
// enableCustom: false, // 是否自定义窗体
// position: new TMap.LatLng(28.900484, 118.508882), // 初始标点坐标
position: new TMap.LatLng(0, 0), // 初始标点坐标
offset: {
// 信息窗体的偏移量
y: -30,
x: 0,
},
// content: `<div style="width: 250px;height: 134px;padding:16px; background-color: white;"></div>`, // 必须设置一个底边的dom,否则会出现白边
})
结尾
本文仅记录个人项目的技术整理,在封装或是调用等方面上会有所欠缺,欢迎大佬指正补充相关方面的技术博客与文档。
如果本文有帮助到你,可否给我一个赞,你的支持就是我创作的动力👍。