infoWindow的基本使用方法
// infowidnow 的 innerHTML
var infoWindowContent =
'<div className="custom-infowindow input-card">' +
'<label style="color:grey">故宫博物院</label>' +
'<div class="input-item">' +
'<div class="input-item-prepend">' +
'<span class="input-item-text" >经纬度</span>' +
'</div>' +
'<input id="lnglat" type="text" />' +
'</div>' +
// 为 infowindow 添加自定义事件
'<input id="lnglat2container" type="button" class="btn" value="获取该位置经纬度" onclick="getLngLat()"/>' +
'</div>';
// 创建一个自定义内容的 infowindow 实例
var infoWindow = new AMap.InfoWindow({
position: lnglat,
offset: new AMap.Pixel(0, -30),
content: infoWindowContent
});
- 如上代码所示: 使用
new AMap.InfoWindow便可以创建一个简单的infoWindow信息窗体
动态创建infoWindow窗体内容
import { h, render, getCurrentInstance } from "vue"
interface IUseInfoWindowReturn {
readonly infoWindow: AMap.InfoWindow | null
readonly container: HTMLDivElement | null
getInfoWindow: () => AMap.InfoWindow
openInfoWindow: (params: IOpenInfoWindowParams) => void
closeInfoWindow: () => void
destroyInfoWindow: () => void
}
interface IOpenInfoWindowParams {
mapInstance: AMap.Map,
position: AMap.LngLat | [number, number],
data: any,
component: Component,
allowScroll?: boolean,
events?: Record<string, (...args: any[]) => void>
}
//#region useInfoWindow: 生成infoWindow
async function useInfoWindow(): Promise<IUseInfoWindowReturn> {
let infoWindow: AMap.InfoWindow | null = null
let container: HTMLDivElement | null = null
const internalInstance = getCurrentInstance()
const appContext = internalInstance?.appContext
const $Store = useStore() // 用于获取在pinia中的全局AMap
const AMap = await $Store.initAMap()
//#region 1. getInfoWindow:初始化 InfoWindow 实例
const getInfoWindow = (): AMap.InfoWindow => {
if (!infoWindow) {
infoWindow = new AMap.InfoWindow({
offset: new AMap.Pixel(0, -30),
isCustom: true,
autoMove: true,
})
}
return infoWindow
}
//#endregion
//#region 2. 打开 InfoWindow
const openInfoWindow = (
{
mapInstance, // 当前的地图实例
position, // infowindow的打开坐标
data, // 传入组件的数据
component, // 组件
allowScroll = false, // 默认不允许在信息窗口上滚动鼠标缩放地图
events = {} // 在组件上挂载的自定义事件
}: IOpenInfoWindowParams
) => {
try {
const iw = getInfoWindow()
closeInfoWindow() // 打开前先清理旧内容
container = document.createElement("div")
container.classList.add('info_window_container')
const vNode = h(component, {
data, infoWindow: iw,
...Object.fromEntries(
Object.entries(events).map(([name, fn]) => [
"on" + name[0].toUpperCase() + name.slice(1),
fn
])
)
}) // 所有的自定义事件都以on开头
if (!allowScroll) {
const onEnter = () => mapInstance.setStatus({ scrollWheel: false })
const onLeave = () => mapInstance.setStatus({ scrollWheel: true })
container.addEventListener("mouseenter", onEnter)
container.addEventListener("mouseleave", onLeave)
} // 禁止滚轮事件
// 关联上下文, 否则组件的中useRouter/pinia等无法使用
if (appContext) {
vNode.appContext = appContext;
}
render(vNode, container)
iw.setContent(container)
iw.open(mapInstance, position)
} catch (err) {
console.log(err)
}
}
//#endregion
//#region 3. 关闭 InfoWindow
const closeInfoWindow = () => {
if (infoWindow) {
infoWindow.close()
const content = infoWindow.getContent()
if (content instanceof HTMLElement) {
render(null, content) // 卸载旧 vnode
}
}
}
//#endregion
//#region 4. 销毁 InfoWindow
const destroyInfoWindow = () => {
closeInfoWindow()
infoWindow = null
container = null
}
//#endregion
//#region 5. 返回一个可始终访问最新 infoWindow 的对象
return {
get infoWindow() {
return infoWindow
},
get container() {
return container
},
getInfoWindow,
openInfoWindow,
closeInfoWindow,
destroyInfoWindow,
}
//#endregion
}
//#endregion
对应的组件需要接收的props
- 在组件的props中需要接data, infowWindow两个属性
interface IInfoComProps {
data: {
location: ILocation
}
infoWindow: AMap.InfoWindow
}
const $props = defineProps<IInfoComProps>()
调用hook动态生成信息窗体
- 初始化hook
let INFOWINDOW: IUseInfoWindowReturn = null
async function initHooks() {
INFOWINDOW = await $keyAreaHooks.useInfoWindow()
}
- 调用一个组件来动态地生成信息窗体
// 以一个labelMarker的右键点击事件为例
async function onLabelMarkerRightClick(e) {
const location: ILocation = e.target.getExtData().location
if (INFOWINDOW) {
INFOWINDOW.closeInfoWindow()
INFOWINDOW.openInfoWindow({
mapInstance,
position: new AMap.LngLat(location.lng, location.lat),
data: { location },
component: $constants.infoWindowType.lcoationMarkerInfo, // 组件
events: {
edit: onLocationEdit,
del: onLocationDel
} // 在组件内部有自定义事件edit与del, 它们会经过处理以onEdit与onDel的形式挂载到组件上
})
}
}
- 附录: 组件中的自定义事件的触发
//#region 业务逻辑: 修改
function onEdit() {
$emits('edit', { locationDetail: locationDetail.value })
}
//#endregion
//#region 业务逻辑: 删除
function onDel() {
$emits('del', { locationDetail: locationDetail.value })
}
//#endregion