开发一个 Vue3 的地图位置选择组件
效果预览
源码
<template>
<div id="amap-container" class="h-96 w-full"></div>
</template>
<script lang="ts">
import { defineComponent, ref, watch } from "vue";
import AMapLoader from "@amap/amap-jsapi-loader";
import { useGlobalSetting } from "@/hooks/setting";
import _ from "lodash";
// 页面 map 实例,在 AMapLoader.load 之后加载
var map = null;
// 全局 AMap 实例,在 AMapLoader.load 之后加载
var AMap = null;
// 内部经纬度保存对象
var innerValRef = ref<LngLat>(null);
// 位置指示标记
var marker = null;
// 初始位置。一开始就初始化,之所以不保存到 innerValRef 是因为此时 innerValRef 的监听中的操作尚未可用。
var initPos: LngLat;
export interface LngLat {
lng: Number;
lat: Number;
}
async function loadAmap() {
try {
await AMapLoader.load({
key: useGlobalSetting ().amapKey, // 申请好的 Web 端开发者 Key,首次调用 load 时必填
version: "1.4.15",
plugins: [],
AMapUI: {
version: "1.1",
plugins: [],
},
Loca: {
version: "1.3.2",
},
});
AMap = globalThis.AMap;
map = new AMap.Map("amap-container", {
zoom: 11, // 级别
center: [initPos.lng, initPos.lat], // 中心点坐标
viewMode: "3D", // 使用 3D 视图
});
map.on("click", handleClick);
innerValRef.value = initPos;
} catch (error) {
console.log(error);
}
}
var handleClick = (e) => {
const pos: LngLat = { lng: e.lnglat.getLng(), lat: e.lnglat.getLat() };
innerValRef.value = pos;
};
var setMarker = (pos: LngLat) => {
if (marker != null) {
map.remove(marker);
}
marker = new AMap.Marker({
position: new AMap.LngLat(pos.lng, pos.lat),
title: "位置",
});
map.add(marker);
console.log("setMarker");
};
export default defineComponent({
props: {
lng: Number,
lat: Number,
},
mounted() {
loadAmap();
},
setup(props, { attrs, slots, emit }) {
initPos = { lng: props.lng, lat: props.lat };
watch(
() => innerValRef.value,
(cur, prev) => {
setMarker(cur);
emit("update:lng", cur.lng);
emit("update:lat", cur.lat);
}
);
watch(
() => props.lng,
(cur: any, prev) => {
innerValRef.value.lng = cur;
setMarker(innerValRef.value);
}
);
watch(
() => props.lat,
(cur: any, prev) => {
innerValRef.value.lat = cur;
setMarker(innerValRef.value);
}
);
return {};
},
});
</script>
使用方法
<n-form-item path="location" label="所在位置">
<n-input-number
:step="0.01"
v-model:value="model.location.lng"
placeholder="ModuleName"
class="mr-2"
/>
<n-input-number :step="0.01" v-model:value="model.location.lat" placeholder="ModuleName" />
</n-form-item>
<amap-location-selector
v-model:lng="model.location.lng"
v-model:lat="model.location.lat"
class="mb-2"
></amap-location-selector>
原理
v-model:propName="xx"
相当于
:propName="xx"
@update:propName="xx = $event"
据此可进行双向绑定。