天地图按地名搜索+openlayer+vue3

  • 使用element-plus组件库
  • 安装ol
  • npm i ol -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>
  • 结果 
  • 按地名搜索

 选中并标注

也可以在地图上点中进行标注

  • 9
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值