- 使用element-plus组件库
- 安装ol
-
npm i ol -s
- 安装axios (调用天地图api http://lbs.tianditu.gov.cn/server/search.html)
-
npm i axios -s
- 主要代码
-
<template> <div class="my-add-maker-box"> <div class="my-point-box"> <span>经度lng:</span> <el-input v-model.trim="pointData.lng" :disabled="true" placeholder="请点击下面地图进行标注" /> <span>纬度lat:</span> <el-input v-model.trim="pointData.lat" :disabled="true" placeholder="请点击下面地图进行标注" /> </div> <div class="my-map-box" id="map" :key="keyMap"> <div class="my-map-search"> <el-input v-model="param.data.postStr.keyWord" placeholder="请输入地名"> <template #append> <el-button :icon="Search" @click="searchHandle" /> </template> </el-input> <div class="my-map-clear" @click="clearMarker">清除标注</div> <div class="my-search-result" v-if="searchShow"> <div v-if="searchResult.data == null" style="margin-left: 150px; font-size: 20px; color: #888;">暂无数据</div> <div v-else class="my-search-result-item" v-for="(item, index) in searchResult.data" :key="index" @click="clickMarker(item)">{{ item.name }} </div> </div> </div> </div> </div> </template> <script lang='ts' setup> import { ref, reactive, onMounted } from 'vue' //导入相关配置信息 import 'ol/css'; import { Map, View, Feature } from 'ol' import { Style, Icon } from 'ol/style' import { Point } from 'ol/geom'; import { Vector as SourceVec, XYZ, } from 'ol/source' import { Vector as LayerVec } from 'ol/layer' import TileLayer from 'ol/layer/Tile' import { defaults as defaultControls, MousePosition, } from "ol/control" import axios from 'axios' import { Search } from '@element-plus/icons-vue' let myMap: any = null let myView: any = null let keyMap: any = ref(Math.random()) let vectorLayer: any = null let searchResult = reactive({ data: null }) let searchShow = ref(false) let pointData = reactive({ lng: '', lat: '' }) // url const url = ref('http://api.tianditu.gov.cn/v2/search') // 参数 let param = reactive({ data: { postStr: { keyWord: '', level: 18, mapBound: "116.02524,39.83833,116.65592,39.99185", queryType: 1, start: 0, count: 10 }, type: 'query', tk: '37c72a79fe4c6a1b3fa6b1435214b378' } }) onMounted(() => { // console.log('initMap') setTimeout(() => { myMap = new Map({ target: 'map', //图层数组 layers layers: [ new TileLayer({ source: new XYZ({ crossOrigin: 'anonymous', url: 'https://t0.tianditu.gov.cn/DataServer?T=vec_w&x={x}&y={y}&l={z}&tk=37c72a79fe4c6a1b3fa6b1435214b378' }) }), new TileLayer({ source: new XYZ({ crossOrigin: 'anonymous', url: 'https://t0.tianditu.gov.cn/DataServer?T=cva_w&x={x}&y={y}&l={z}&tk=37c72a79fe4c6a1b3fa6b1435214b378' }) }) ], //视图 View view: new View({ projection: "EPSG:4326", center: [120.15373797456354, 30.291315691648734], zoom: 15, maxZoom: 17, minZoom: 3, }), //默认控件 controls: defaultControls({ zoom: false, rotate: false, attribution: false, }).extend([ //添加新控件 // new MousePosition(), ]) }) // 获取地图视图 myView = myMap.getView() // setMarker([120.15373797456354, 30.291315691648734]) myMap.on('singleclick', function (e: any) { setMarker(e.coordinate) }) }, 1); }) // 标注点 const setMarker = (point: any) => { //移出给定的图层 myMap.removeLayer(vectorLayer) // 创建矢量容器 let vectorSource = new SourceVec({}) //创建图标特性 let iconFeature = new Feature({ geometry: new Point(point, "XY") }) //将图标特性添加进矢量中 vectorSource.addFeature(iconFeature) //创建图标样式 let iconStyle = new Style({ image: new Icon({ opacity: 0.75, src: require('@/assets/images/marker-icon.png'), // offset: [-20, -40], // offsetOrigin: 'bottom-right', size: [30, 65] }) }) //创建矢量层 vectorLayer = new LayerVec({ source: vectorSource, style: iconStyle }); //添加进map // removeLayer myMap.addLayer(vectorLayer); param.data.postStr.keyWord = '' searchShow.value = false pointData.lng = point[0] pointData.lat = point[1] } // 清除标注点 const clearMarker = () => { //移出给定的图层 myMap.removeLayer(vectorLayer) pointData.lng = '' pointData.lat = '' } // 点中某个结果 const clickMarker = (item: object) => { setMarker(item.lonlat.split(',')) myView.setCenter(item.lonlat.split(',')) param.data.postStr.keyWord = '' searchShow.value = false } //搜索 const searchHandle = () => { // 地名查询 axios({ method: 'GET', url: url.value, params: param.data }).then(function (res) { console.log(res.data.pois) searchShow.value = true if (res.data.pois) { searchResult.data = res.data.pois } else { searchResult.data = null } console.log(res.data) }) } </script> <style scoped lang='less'> .my-add-maker-box { width: 100vw; // border: 1px solid #eee; .my-point-box { width: 900px; margin: auto; display: flex; justify-content: center; align-items: center; margin-bottom: 20px; span { display: inline-block; width: 200px; } } .my-map-box { width: 900px; height: 500px; margin: auto; position: relative; z-index: 1; .my-map-search { position: absolute; top: 5px; left: 10px; z-index: 99; .my-map-clear { position: absolute; top: 0; left: 380px; z-index: 999; width: 90px; text-align: center; line-height: 30px; border: 1px solid #dcdfe6; background-color: #f5f7fa; border-radius: 3px; cursor: pointer; color: #909399; &:hover { background-color: #ecf5ff; color: #409eff; } } .my-search-result { position: absolute; top: 31px; left: 0; z-index: 999; width: 371px; max-height: 260px; border: 1px solid #eee; box-sizing: border-box; background-color: #fff; overflow: auto; padding: 10px 0; .my-search-result-item { width: 100%; padding: 8px 15px; box-sizing: border-box; cursor: pointer; &:hover { background-color: #eee; } } } } /deep/ .el-input-group { width: 371px; } } } </style>
- 结果
- 按地名搜索
选中并标注
也可以在地图上点中进行标注