integrations
本文回答:Vite / Vue 3 / Vue 2 / React / 纯 HTML 五种集成方式的起点样板。
一、Vite + Vanilla JS
npm create vite@latest my-app -- --template vanilla
cd my-app
npm i vjmap vjmapext
src/main.js:
import "vjmap/dist/vjmap.min.css";
import vjmap from "vjmap";
async function main() {
const svc = new vjmap.Service(SERVICE_URL, TOKEN);
const res = await svc.openMap({ mapid: "sys_zp", mapopenway: vjmap.MapOpenWay.GeomRender });
if (res.error) throw new Error(res.error);
const prj = new vjmap.GeoProjection(res.bounds);
const map = new vjmap.Map({
container: "map",
style: svc.vectorStyle(),
center: prj.toLngLat(prj.getMapExtent().center()),
zoom: 2,
renderWorldCopies: false
});
map.attach(svc, prj);
await map.onLoad();
}
main();
GeoProjection构造函数在运行时兼容res.bounds字符串(内部自动GeoBounds.fromString),但 d.ts 只声明了GeoBounds——TS 工程须显式new vjmap.GeoProjection(vjmap.GeoBounds.fromString(res.bounds))。
二、Vue 3 + <script setup>
<script setup lang="ts">
import "vjmap/dist/vjmap.min.css";
import vjmap, { type Map } from "vjmap";
import { MapCadLayer } from "vjmapext";
import { onMounted, onUnmounted } from "vue";
let map: Map | null = null;
onMounted(async () => {
const svc = new vjmap.Service(SERVICE_URL, TOKEN);
const res = await svc.openMap({ mapid: "sys_zp", mapopenway: vjmap.MapOpenWay.GeomRender });
if (res.error) throw new Error(String(res.error));
const prj = new vjmap.GeoProjection(res.bounds);
map = new vjmap.Map({
container: "map-container",
style: svc.rasterStyle(),
center: prj.toLngLat(prj.getMapExtent().center()),
zoom: 2,
renderWorldCopies: false
});
map.attach(svc, prj);
await map.onLoad();
const cad = new MapCadLayer();
map.addControl(cad);
cad.createUI({ theme: "dark" });
});
onUnmounted(() => {
map?.remove();
map = null;
});
</script>
<template>
<div id="map-container" />
</template>
<style scoped>
#map-container { position: absolute; inset: 0; background: #022b4f; }
</style>
三、Vue 2
<template>
<div id="map-container" />
</template>
<script>
import "vjmap/dist/vjmap.min.css";
import vjmap from "vjmap";
import { MapCadLayer } from "vjmapext";
export default {
data() { return { map: null }; },
async mounted() {
const svc = new vjmap.Service(this.$env.serviceUrl, this.$env.token);
const res = await svc.openMap({
mapid: "sys_zp",
mapopenway: vjmap.MapOpenWay.GeomRender
});
if (res.error) throw new Error(res.error);
const prj = new vjmap.GeoProjection(res.bounds);
this.map = new vjmap.Map({
container: "map-container",
style: svc.rasterStyle(),
center: prj.toLngLat(prj.getMapExtent().center()),
zoom: 2
});
this.map.attach(svc, prj);
await this.map.onLoad();
const cad = new MapCadLayer();
this.map.addControl(cad);
},
beforeDestroy() {
this.map?.remove();
this.map = null;
}
};
</script>
四、React(Hooks)
import "vjmap/dist/vjmap.min.css";
import vjmap from "vjmap";
import { MapCadLayer } from "vjmapext";
import { useEffect, useRef } from "react";
export default function MapView() {
const ref = useRef(null);
useEffect(() => {
let map;
let disposed = false;
(async () => {
const svc = new vjmap.Service(process.env.REACT_APP_SERVICE, process.env.REACT_APP_TOKEN);
const res = await svc.openMap({ mapid: "sys_zp", mapopenway: vjmap.MapOpenWay.GeomRender });
if (res.error || disposed) return;
const prj = new vjmap.GeoProjection(res.bounds);
map = new vjmap.Map({
container: ref.current,
style: svc.rasterStyle(),
center: prj.toLngLat(prj.getMapExtent().center()),
zoom: 2
});
map.attach(svc, prj);
await map.onLoad();
if (disposed) { map.remove(); return; }
const cad = new MapCadLayer();
map.addControl(cad);
})();
return () => { disposed = true; map?.remove(); };
}, []);
return <div ref={ref} style={{ position: "absolute", inset: 0 }} />;
}
注意 React StrictMode 会双调用 useEffect,闭包中的
disposed和map?.remove()必不可少。
五、纯 HTML <script>
<!DOCTYPE html>
<html>
<head>
<link rel="stylesheet" href="https://vjmap.com/demo/js/vjmap/vjmap.min.css" />
<script src="https://vjmap.com/demo/js/vjmap/vjmap.min.js"></script>
<script src="https://vjmap.com/demo/js/vjmap/vjmapext.min.js"></script><!-- 注意在 /js/vjmap/ 目录下 -->
</head>
<body style="margin:0;background:#022B4F;">
<div id="map" style="position:absolute;inset:0"></div>
<script>
(async () => {
const svc = new vjmap.Service(SERVICE_URL, TOKEN);
const res = await svc.openMap({ mapid: "sys_zp", mapopenway: vjmap.MapOpenWay.GeomRender });
if (res.error) return console.error(res.error);
const prj = new vjmap.GeoProjection(res.bounds);
const map = new vjmap.Map({
container: "map",
style: svc.rasterStyle(),
center: prj.toLngLat(prj.getMapExtent().center()),
zoom: 2
});
map.attach(svc, prj);
await map.onLoad();
const cad = new vjmapext.MapCadLayer();
map.addControl(cad);
cad.createUI({ theme: "dark" });
})();
</script>
</body>
</html>
六、不同框架共性注意
- 所有框架都要
await map.onLoad()之后再 add source / layer / Marker / Control。 - Vue
<keep-alive>场景用activated/deactivated控制 map 的remove/resize。 - React 热更新(HMR)时,旧 map 会泄漏,需在 effect cleanup 中
map.remove()。 - SSR 框架(Next/Nuxt)中 vjmap 只在客户端可用:
if (typeof window !== "undefined") { ... },或用动态import。