一、前期
1、腾讯地图官网获取key值 ,控制台——应用管理——创建应用
2、创建应用成功后设置key值
二、功能
1、引入腾讯地图的js,在vue的public文件夹的index.html中加上以下语句
<script charset="utf-8" src="https://map.qq.com/api/gljs?v=1.exp&key=在官网控制台获取的key"></script>
2、创建地图组件Map.vue——初始化地图
<div id="map" />
初始化地图和中心点 ,监控地图拖动
注: map和marKerLayer不要写在reactive,ref中否则在之后修改中心点时会报错
Failed to execute ‘postMessage‘ on ‘Worker‘: [object Object] could not be cloned
var map = null // 地图
var markerLayer = null// 点标记
// 初始化地图/定位
const getinitChange = (lat, lng) => {
console.log(lat, lng)
// 定义地图中心点坐标
const myLatlng = new window.TMap.LatLng(lat, lng)
vueConfig.lat = lat
vueConfig.lng = lng
// 定义map变量,调用 window.TMap.Map() 构造函数创建地图
map = new window.TMap.Map(document.getElementById('map'), {
center: myLatlng, // 设置地图中心点坐标
zoom: 17.2 // 设置地图缩放级别
})
var geometries = {
id: '1', // 点标记唯一标识,后续如果有删除、修改位置等操作,都需要此id
styleId: 'myStyle', // 指定样式id
position: myLatlng // 点标记坐标位置
}
markerLayer = new window.TMap.MultiMarker({
map: map,
styles: {
// 创建一个styleId为"myStyle"的样式(styles的子属性名即为styleId)
myStyle: new window.TMap.MarkerStyle({
width: 25, // 点标记样式宽度(像素)
height: 30 // 点标记样式高度(像素)
})
},
// 点标记数据数组
geometries: [geometries]
})
// 监听地图正在平移的状态
map.on('pan', function() {
markerLayer.updateGeometries([
{
'styleId': 'myStyle',
'id': '1',
'position': map.getCenter()
}
])
})
// 监听地图结束平移
map.on('panend', function() { // 拖拽结束时获取地址
getInverseAnalysis()
})
}
3、关键字搜索
<el-autocomplete
v-model="vueConfig.address"
value-key="title"
:fetch-suggestions="querySearch"
:trigger-on-focus="false"
@select="handleSelect"
>
<template #append>
<el-button icon="el-icon-search" />
</template>
</el-autocomplete>
// 关键字查询
const querySearch = (queryString, callback) => {
const url = 'https://apis.map.qq.com/ws/place/v1/suggestion' // 关键字查询
jsonp(url, {
key: vueConfig.key,
keyword: queryString,
output: 'jsonp'
})
.then(res => {
if (res.status == 0) {
const list = res.data
callback(list)
} else {
ElMessage({
type: 'error',
message: res.message
})
}
})
}
// 选择地址
const handleSelect = (item) => {
vueConfig.lat = item.location.lat
vueConfig.lng = item.location.lng
vueConfig.location = item
vueConfig.ispan = false
setInitChange()
}
4、修改地图位置
// 修改地图位置
const setInitChange = () => {
map.setCenter(new window.TMap.LatLng(vueConfig.lat, vueConfig.lng))
markerLayer.updateGeometries([
{
'styleId': 'myStyle',
'id': '1',
'position': new window.TMap.LatLng(vueConfig.lat, vueConfig.lng)
}
])
}
5、获取当前位置,初始化地图
// 获取当前位置
const getNowLngAndLat = () => {
const url = 'https://apis.map.qq.com/ws/location/v1/ip'
jsonp(url, {
key: vueConfig.key,
output: 'jsonp'
})
.then(res => {
if (res.status == 0) {
vueConfig.lat = res.result.location.lat
vueConfig.lng = res.result.location.lng
getinitChange(vueConfig.lat, vueConfig.lng)
} else {
ElMessage({
type: 'error',
message: res.message
})
}
})
}
6、逆解析地址
// 逆解析地址
const getInverseAnalysis = () => {
const location = `${map.getCenter().lat},${map.getCenter().lng}`
const url = 'https://apis.map.qq.com/ws/geocoder/v1/?location='
jsonp(url, {
location: location,
output: 'jsonp',
key: vueConfig.key
})
.then(res => {
if (res.status == 0) {
if (vueConfig.ispan) {
vueConfig.lat = res.result.location.lat
vueConfig.address = res.result.formatted_addresses.recommend
vueConfig.lng = res.result.location.lng
}
vueConfig.ispan = true
} else {
ElMessage({
type: 'error',
message: res.message
})
}
})
.catch(err => {
console.log(err)
})
}
三、 完整代码
<template>
<el-dialog
v-model="vueConfig.dialogAddressVisible"
title="获取经纬度"
:close-on-click-modal="false"
:destroy-on-close="true"
:append-to-body="true"
width="55%"
@close="handleClose()"
>
<div class="map-input">
<el-autocomplete
v-model="vueConfig.address"
value-key="title"
:fetch-suggestions="querySearch"
:trigger-on-focus="false"
@select="handleSelect"
>
<template #append>
<el-button icon="el-icon-search" />
</template>
</el-autocomplete>
</div>
<div id="map" />
<template #footer>
<span class="dialog-footer">
<el-button @click="handleClose()">取消</el-button>
<el-button type="primary" @click="confirmMap">确认地址</el-button>
</span>
</template>
</el-dialog>
</template>
<script >
import { reactive, nextTick, watch } from 'vue'
import { jsonp } from 'vue-jsonp'
import { ElMessage } from 'element-plus'
export default {
props: {
lat: {
type: Number,
default: 0
},
lng: {
type: Number,
default: 0
},
address: {
type: String,
default: ''
},
dialogVisible: {
type: Boolean,
default: false
}
},
emits: ['sure', 'change'],
setup(props, ctx) {
var map = null // 地图
var markerLayer = null// 点标记
const vueConfig = reactive({
dialogAddressVisible: false,
address: '', // 地址
lat: 0,
lng: 0,
key: '你申请的key值',
ispan: false,
location: {}// 地址详情
})
watch(
() => props.dialogVisible,
() => {
vueConfig.dialogAddressVisible = props.dialogVisible
vueConfig.address = props.address
vueConfig.lat = props.lat
vueConfig.lng = props.lng
nextTick(() => {
if (vueConfig.dialogAddressVisible) {
if (!props.lat) {
getNowLngAndLat() //根据ip获取当前位置
} else {
getinitChange(props.lat, props.lng)//初始化地图
}
}
})
},
{ immediate: true }
)
// 关键字查询
const querySearch = (queryString, callback) => {
const url = 'https://apis.map.qq.com/ws/place/v1/suggestion' // 关键字查询
jsonp(url, {
key: vueConfig.key,
keyword: queryString,
output: 'jsonp'
})
.then(res => {
if (res.status == 0) {
const list = res.data
callback(list)
} else {
ElMessage({
type: 'error',
message: res.message
})
}
})
}
// 选择地址
const handleSelect = (item) => {
vueConfig.lat = item.location.lat
vueConfig.lng = item.location.lng
vueConfig.location = item
vueConfig.ispan = false
setInitChange()
}
// 修改地图位置
const setInitChange = () => {
map.setCenter(new window.TMap.LatLng(vueConfig.lat, vueConfig.lng))
markerLayer.updateGeometries([
{
'styleId': 'myStyle',
'id': '1',
'position': new window.TMap.LatLng(vueConfig.lat, vueConfig.lng)
}
])
}
// 获取当前位置
const getNowLngAndLat = () => {
const url = 'https://apis.map.qq.com/ws/location/v1/ip'
jsonp(url, {
key: vueConfig.key,
output: 'jsonp'
})
.then(res => {
if (res.status == 0) {
vueConfig.lat = res.result.location.lat
vueConfig.lng = res.result.location.lng
getinitChange(vueConfig.lat, vueConfig.lng)
} else {
ElMessage({
type: 'error',
message: res.message
})
}
})
}
// 逆解析地址
const getInverseAnalysis = () => {
const location = `${map.getCenter().lat},${map.getCenter().lng}`
const url = 'https://apis.map.qq.com/ws/geocoder/v1/?location='
jsonp(url, {
location: location,
output: 'jsonp',
key: vueConfig.key
})
.then(res => {
if (res.status == 0) {
if (vueConfig.ispan) {
vueConfig.lat = res.result.location.lat
vueConfig.address = res.result.formatted_addresses.recommend
vueConfig.lng = res.result.location.lng
}
vueConfig.ispan = true
} else {
ElMessage({
type: 'error',
message: res.message
})
}
})
.catch(err => {
console.log(err)
})
}
// 初始化地图/定位
const getinitChange = (lat, lng) => {
console.log(lat, lng)
// 定义地图中心点坐标
const myLatlng = new window.TMap.LatLng(lat, lng)
vueConfig.lat = lat
vueConfig.lng = lng
// 定义map变量,调用 window.TMap.Map() 构造函数创建地图
map = new window.TMap.Map(document.getElementById('map'), {
center: myLatlng, // 设置地图中心点坐标
zoom: 17.2 // 设置地图缩放级别
})
var geometries = {
id: '1', // 点标记唯一标识,后续如果有删除、修改位置等操作,都需要此id
styleId: 'myStyle', // 指定样式id
position: myLatlng // 点标记坐标位置
}
markerLayer = new window.TMap.MultiMarker({
map: map,
styles: {
// 创建一个styleId为"myStyle"的样式(styles的子属性名即为styleId)
myStyle: new window.TMap.MarkerStyle({
width: 25, // 点标记样式宽度(像素)
height: 30 // 点标记样式高度(像素)
})
},
// 点标记数据数组
geometries: [geometries]
})
// 监听地图正在平移的状态
map.on('pan', function() {
markerLayer.updateGeometries([
{
'styleId': 'myStyle',
'id': '1',
'position': map.getCenter()
}
])
})
// 监听地图结束平移
map.on('panend', function() { // 拖拽结束时获取地址
getInverseAnalysis()
})
}
const resetFormData = () => { //清空地图
map = null
markerLayer = null
}
const handleClose = () => { //关闭
resetFormData()
ctx.emit('change', null)
}
const confirmMap = () => {//确认地址
const location = {
lat: vueConfig.lat,
lng: vueConfig.lng,
address: vueConfig.address
}
if (!vueConfig.address) {
ElMessage({
type: 'warning',
message: '请获取地址/经纬度'
})
return false
}
ctx.emit('sure', location)
}
return {
vueConfig,
getinitChange,
handleSelect,
querySearch,
setInitChange,
map,
markerLayer,
confirmMap,
getInverseAnalysis,
handleClose,
resetFormData
}
}
}
</script>
<style lang="scss" scoped>
.map-input {
margin-bottom: 20px;
display: flex;
:deep(.el-autocomplete) {
width: 100%;
}
}
.map {
position: relative;
}
.biadian {
position: absolute;
top: calc(50% - 25px);
left: 50%;
transform: translate(-50%, -50%);
width: 50px;
height: 50px;
}
</style>