Vue + element实现电子围栏功能, 根据省市区选择围栏, 自定义围栏 ,手动输入地名围栏, 保存围栏,清除围栏,加载围栏,批量检测标点是否在围栏内。
1:第一步 下载vue-amap插件(0.5.10版本号)
npm install vue-amap
2:第二步 下载element-china-area-data插件 用于选择省市区 (6.1.0版本号)
npm install element-china-area-data
3:第三步 在main.js入口文件 注册vue-amap 提前在高德开放平台申请你的key
import VueAMap from "vue-amap";Vue.use(VueAMap);
window._AMapSecurityConfig = {securityJsCode: "高德密钥",
};
VueAMap.initAMapApiLoader({key: "高德key",plugin: ["AMap.Autocomplete", //输入提示插件"AMap.PlaceSearch", //POI搜索插件"AMap.Scale", //右下角缩略图插件 比例尺"AMap.OverView", //地图鹰眼插件"AMap.ToolBar", //地图工具条"AMap.Geolocation", //定位控件,用来获取和展示用户主机所在的经纬度位置"AMap.Geocoder", // 逆地理编码,通过经纬度获取地址所在位置详细信息"AMap.MapType","AMap.PolyEditor","AMap.CircleEditor","AMap.MouseTool", // 鼠标绘图"AMap.PolygonEditor", // 编辑围栏// 根据需求选用],uiVersion: "1.0", // 地图ui版本v: "1.4.4", // amap版本
});
4.第四步直接复制我的vue文件 就完成了
<template><div style="width: 100%; height: 600px"><el-row :gutter="10"><el-col :span="4"><el-cascadersize="large"ref="cascader":options="options"v-model="provinces"@change="handleChange"placeholder="请选择省市区":props="props"></el-cascader><el-input placeholder="最下级区县城市" v-model="address"><template slot="append"><el-button @click="addDistrictFence(address)">搜索</el-button></template></el-input><el-button type="primary" @click="startDrawPolygon">绘制自定义围栏</el-button><el-button @click="saveFences">保存围栏</el-button><el-button @click="loadFences">加载围栏</el-button><el-button @click="clearFences">清除围栏</el-button><el-divider></el-divider><el-button @click="checkAllPoints">批量检测点是否在围栏内</el-button><el-table :data="pointsResult" style="margin: 10px 0"><el-table-column prop="lng" label="经度"></el-table-column><el-table-column prop="lat" label="纬度"></el-table-column><el-table-column prop="text" label="是否在围栏"><!-- <template slot-scope="scope"><el-tag :type="scope.row.inFence ? 'success' : 'danger'">{{ scope.row.inFence ? "是" : "否" }}</el-tag></template> --></el-table-column></el-table><el-divider></el-divider><div v-for="f in fences" :key="f.id"><el-tag>{{ f.name || "围栏" + f.id }}</el-tag></div></el-col><el-col :span="20"><el-amapref="amap":zoom="zoom":center="center"class="amap"style="height: 500px; width: 100%"><el-amap-polygonv-for="f in fences":key="f.id":path="f.path":fillColor="'#1791fc'":fillOpacity="0.35":strokeColor="'#FF33FF'":label="{ content: f.name, offset: [-10, -10] }"></el-amap-polygon><el-amap-markerv-for="(p, idx) in pointsList":key="idx":position="[p.lng, p.lat]":label="{ content: getFenceName(p, idx), offset: [-10, -10] }"/></el-amap></el-col></el-row></div>
</template><script>
import { regionData } from "element-china-area-data"; //引入
export default {name: "fence",props: {points: {type: Array,default: () => [], // [{lng, lat}]},},data() {return {zoom: 14,center: [116.397428, 39.90923],map: null,mouseTool: null,mouseToolReady: false,idCounter: 0, // 用于生成唯一IDfences: [],//省市区选择options: regionData, //选择格式provinces: [], //省市区绑定数组props: {label: "label",value: "value",children: "children",checkStrictly: true,},// 检测是否在电子围栏范围内pointsList: [{ lng: 116.400428, lat: 39.91223 },{ lng: 116.410428, lat: 39.91223 },{ lng: 116.402, lat: 39.917 },],pointsResult: [],address: "",};},mounted() {this.waitForMapReady();},methods: {checkAllPoints() {this.pointsResult = this.pointsList.map((p, i) => {return this.isPointInAnyFence(p, i);});// this.pointsList = this.pointsResult; // 更新 marker 图标状态},// 检测是否在电子围栏内isPointInAnyFence(p, i) {const lnglat = new AMap.LngLat(p.lng, p.lat);const found = this.fences.find((f) => {const polygon = new AMap.Polygon({ path: f.path });return polygon.contains(lnglat);});let text = found ? "在围栏内" + found.name : "不在围栏内" + (i + 1);return { ...p, text };},// 初始化地图waitForMapReady() {const check = () => {const mapInstance = this.$refs.amap && this.$refs.amap.$$getInstance();if (mapInstance) {this.map = mapInstance;this.map.plugin(["AMap.MouseTool", "AMap.DistrictSearch"], () => {this.mouseTool = new AMap.MouseTool(this.map);this.mouseToolReady = true;this.checkAllPoints();});} else {setTimeout(check, 200);}};console.log(this.options, "options");check();},// 自定义电子围栏绘制startDrawPolygon() {if (!this.mouseToolReady || !this.mouseTool) {this.$message.error("地图未初始化完成,无法绘制围栏");return;}this.mouseTool.polygon({strokeColor: "#FF33FF",fillColor: "#1791fc",fillOpacity: 0.4,});this.mouseTool.on("draw", (e) => {const path = e.obj.getPath().map((p) => [p.lng, p.lat]);// let num = Math.floor(Math.random() * 99999) + 1;this.fences.push({id: this.idCounter++,name: `自定义围栏${this.idCounter}`,path,});this.mouseTool.close(true);this.checkAllPoints();});},// 通过区域名称搜索行政区边界经纬点addDistrictFence(name) {if (!this.map) {this.$message.error("地图未加载完成,请稍后再试");return;}if (!name) {this.$message.error("请输入行政区名称");return;}const district = new AMap.DistrictSearch({subdistrict: 0,extensions: "all",level: "city",});district.search(name, (status, result) => {if (status === "complete" && result.districtList.length > 0) {const districtItem = result.districtList[0];const polylineList = districtItem.boundaries;if (!polylineList || polylineList.length === 0) {this.$message.warning("未获取到行政区边界");return;}console.log(result, "行政区搜索结果");this.center = [districtItem.center.lng, districtItem.center.lat];polylineList.forEach((bound, idx) => {const path = bound.map((p) => {const { lng, lat } = p;return [parseFloat(lng), parseFloat(lat)];});// let num = Math.floor(Math.random() * 99999) + 1;this.fences.push({id: this.idCounter++,name: `${name}边界${idx + 1}`,path,});this.checkAllPoints();});} else {this.$message.error("行政区搜索失败");}});},// 查询标点是否在围栏内 存在时记录存在围栏的idgetFenceName(point, i) {const lnglat = new AMap.LngLat(point.lng, point.lat);const found = this.fences.find((f) => {const polygon = new AMap.Polygon({ path: f.path });return polygon.contains(lnglat);});return found ? "在围栏内" + found.name : "不在围栏内" + (i + 1);},// 保存自定义绘制围栏和通过行政区围栏选择的围栏缓存本地saveFences() {localStorage.setItem("geo-fences", JSON.stringify(this.fences));this.$message.success("已保存围栏");},// 清除地图上的所有电子围栏clearFences() {localStorage.setItem("geo-fences", []);this.fences = [];this.$message.success("已清除围栏");},// 从本地缓存加载电子围栏loadFences() {const raw = localStorage.getItem("geo-fences");if (raw) {try {const parsed = JSON.parse(raw);this.fences = parsed.map((f) => ({...f,path: f.path.map((p) => (Array.isArray(p) ? p : [p.lng, p.lat])),}));this.$forceUpdate();console.log(this.fences, "this.fences");} catch (e) {this.$message.success("暂无缓存围栏");this.fences = [];}}},// 省市区选择变化时触发handleChange(e) {console.log(e, "所选code值");const nodes = this.$refs.cascader.getCheckedNodes();// nodes[0].pathNodes 就是每一层选中的原始节点对象const pathNodes = nodes[0].pathNodes;const cityName = pathNodes.pop();console.log("每一级的原始节点对象:", pathNodes, cityName);if (cityName && cityName.label) {if (cityName.label == "市辖区") {let label = pathNodes[0].label;console.log(label, "市辖区label");this.addDistrictFence(label);} else {console.log(cityName.label, "城市名称");this.addDistrictFence(cityName.label);}} else {this.$message.error("请选择省市区");}},},
};
</script><style scoped>
.amap {border: 1px solid #ccc;border-radius: 6px;
}
</style>