前端vue如何引用(按需加载)百度地图,并组件化封装。
本文详细介绍了如何在Vue项目中使用并按需加载百度地图api,地图初始化,创建标注和信息窗口、搜索功能及事件处理。
·
1.技术选项:
vite+vue3+elementplus
2.实现思路:
1.按需加载如何实现?
要实现按需加载就不能直接在项目的入口文件这种地方去通过script标签引入,这里封装了一个加载百度地图的js方法,实现动态的插入sript脚本
根目录下创建Bmap.js文件
import _loadScript from 'load-script';
export function Map(url) {
return new Promise((resolve, reject) => {
_loadScript(url, (error, script) => {
if (error) {
return reject(error);
}
console.log('====================================');
console.log(script);
console.log('====================================');
resolve(script);
});
});
}
export default function loadBMap() {
return new Promise(function(resolve, reject) {
if (typeof BMap !== 'undefined') {
resolve(BMap);
return true;
}
window.onBMapCallback = function() {
resolve(BMap);
};
let script = document.createElement('script');
script.type = 'text/javascript';
script.src =
'https://api.map.baidu.com/api?v=3.0&ak=自己的';
script.onerror = reject;
document.head.appendChild(script);
});
}
2.初始化加载地图(注意事项)
要初始化加载地图,我们需要确保的时候,在页面绘制完,或者弹框加载完成之后再去调用初始化的方法,否则就会报错。
报错示例:
Cannot read properties of undefined (reading kc )
封装示例图
3.map.js脚本实现如下:
// 加载百度地图
export function LoadBaiduMapScript() {
console.log("百度地图脚本初始化ing----------------");
const BMap_URL =
"https://api.map.baidu.com/api?v=3.0&ak=换成自己的&callback=onBMapCallback";
return new Promise((resolve, _reject) => {
// 如果已加载直接返回
if (typeof BMap !== "undefined") {
resolve(BMap);
return true;
}
// 百度地图异步加载回调处理
window.onBMapCallback = function () {
console.log("百度地图脚本初始化成功...");
resolve(BMap);
};
// 插入script脚本
const scriptNode = document.createElement("script");
scriptNode.setAttribute("type", "text/javascript");
scriptNode.setAttribute("src", BMap_URL);
document.body.appendChild(scriptNode);
});
}
vue代码如下:
注意:该代码的ProModal是本人自己封装的,借鉴即可,原理一致
new BMap 可能会爆红 不用管,不影响使用
一定要在他外层的组件加载完之后 再调用initMap({})等方法,因为我这里使用的是弹框 只需要确定弹框打开之后,再调用就行了,之前使用的一直是onMounted生命周期,导致报错(自己区分场景即可)
<template>
<div class="w-full h-full">
<ProModal
v-model:visible="visible"
width="1200"
@cancel="destroyMap"
title="地图选择"
@ok="handleOk"
:use-type="2"
>
<ElInput
placeholder="请输入地址"
class="mb-2"
style="width: 40%"
v-model="searchValue"
clearable
:readonly="loading"
>
<template #append>
<ElButton type="primary" @click="handleSearch">搜索</ElButton>
</template>
</ElInput>
<div id="container" class="positionbox" v-loading="loading"></div>
</ProModal>
<ElButton type="primary" @click="handleClick">点击弹出地图</ElButton>
</div>
</template>
<script lang="ts" setup>
import { ref, unref, watch } from "vue";
import { ProModal } from "@/components/ProComponents/index";
import { useMessage } from "@/hooks/useMessage";
import { ElButton, ElInput } from "element-plus";
import positionIcon from "@/assets/images/position.png"; //找一个标记地点的图标替代
import { LoadBaiduMapScript } from "./map";
const searchValue = ref(""); //搜索框
const emits = defineEmits(["selectAddress"]);
const visible = ref(false);
const loading = ref(false);
//下方的address lon lat 自己找一个地址的信息 写死就行
const address: any = ref("北京");
const lon: any = ref(116.40); //代表经度 (longitude)
const lat: any = ref(39.90); //代表纬度 (latitude)
const map: any = ref({});
const point: any = ref({});
const marker: any = ref({});
const current: any = ref({});
const message = useMessage();
const handleClick = () => {
visible.value = true;
};
watch(visible, async (newVal) => {
if (newVal) {
await LoadBaiduMapScript();
//必须在实例化之后才能获取到地图实例
await initMap({});
//定位
await browserPosition();
}
});
// 初始百度地图 record可为传参 去修改上次选择的地址
const initMap = (record: any) => {
address.value = record.address ? record.address : "郑州市";
// 1.创建地图实例
map.value = new BMap.Map("container");
lon.value = record?.coordinates?.lon ?? lon.value ?? 116.40;
lat.value = record?.coordinates?.lat ?? lat.value ?? 39.90;
// 2.设置中心点
point.value = new BMap.Point(116.40, 39.90);
console.log("🚀 ~ initMap ~ point.value:", point.value, unref(map));
// // // 3.设置级别
unref(map).centerAndZoom(point.value, 15);
// // 4.开启鼠标滚轮缩放功能。仅对PC上有效
unref(map).enableScrollWheelZoom();
const myIcon = new BMap.Icon(positionIcon, new BMap.Size(23, 25));
marker.value = new BMap.Marker(point.value, myIcon);
unref(map).addOverlay(marker.value); //添加一个标注
// 打开信息窗口
upInfoWindow();
// 点击地图事件
unref(map).addEventListener("click", function (e: any) {
lon.value = e.point.lng;
lat.value = e.point.lat;
point.value = new BMap.Point(lon.value, lat.value);
unref(map).centerAndZoom(point.value, 15);
upInfoWindow();
const gc = new BMap.Geocoder();
gc.getLocation(point.value, (rs: any) => {
if (rs && rs.address) {
address.value = rs.address;
}
});
});
};
// 打开信息窗口
const upInfoWindow = () => {
const opts = {
width: 250, // 信息窗口宽度
height: 120, // 信息窗口高度
title: "经纬度", // 信息窗口标题
};
console.log(unref(address));
const word = `<div>地址:${unref(address)}</div>
<div>经度:${unref(lon)}</div>
<div>纬度:${unref(lat)}</div>`;
const infoWindow = new BMap.InfoWindow(word, opts); // 创建信息窗口对象
unref(map).openInfoWindow(infoWindow, point.value); // 打开信息窗口
// 使信息窗口多次打开
unref(marker).addEventListener("click", function () {
unref(map).openInfoWindow(infoWindow, point.value);
});
};
// 对搜索框中的文字进行逆解析
function geocoderLocation() {
point.value = new BMap.Point(lon.value, lat.value);
unref(map).centerAndZoom(unref(point), 15);
unref(map).addOverlay(new BMap.Marker(unref(point)));
const gc = new BMap.Geocoder();
gc.getLocation(unref(point), (rs: any) => {
console.log(rs);
if (rs && rs.address) {
address.value = rs.address;
upInfoWindow();
}
});
}
// 搜索框改变事件
const handleSearch = () => {
if (searchValue) {
const value = searchValue.value.trim();
//创建地址解析器实例
const myGeo = new BMap.Geocoder();
// 将地址解析结果显示在地图上,并调整地图视野
myGeo.getPoint(
value,
async (point: any) => {
if (point) {
lon.value = point.lng;
lat.value = point.lat;
await geocoderLocation();
} else {
message({ type: "warning", message: "您选择的地址没有解析到结果!" });
}
},
value
);
} else {
message({ type: "warning", message: "搜索框不能为空" });
}
};
// 浏览器定位
function browserPosition() {
loading.value = true;
const geolocation = new BMap.Geolocation();
geolocation.getCurrentPosition((r: any) => {
if (r) {
(lon.value = r.point.lng), (lat.value = r.point.lat), geocoderLocation();
} else {
message({ type: "error", message: "定位失败,请手动输入经纬度" });
}
loading.value = false;
});
}
//销毁地图实例
const destroyMap = () => {
if (map.value) {
// 清除地图上的所有标注、图层等
map.value.clearOverlays();
// 将 map 设为 null
map.value = null;
console.log("地图实例已销毁");
}
};
//确认回调
const handleOk = () => {
destroyMap();
emits("selectAddress", {
address: address.value,
lon: lon.value,
lat: lat.value,
});
};
</script>
<style scoped lang="less">
.positionbox {
width: 77vw;
height: 64vh;
margin-top: 20px;
}
</style>
组件压缩包链接如下:
链接: https://pan.baidu.com/s/1ZNuE8nJ0L93lKYeny0-NPQ?pwd=9527 提取码: 9527 复制这段内容后打开百度网盘手机App,操作更方便哦
实现效果如下
更多推荐
所有评论(0)