vue2+Openlayers实现多图层切换(二)

前言

这是个人对于初学openlayers的总结,如果有不足之处,欢迎大家指正。

在这里插入图片描述

介绍

本文章内容挺简单的,就是实现多个图层的简单切换,相较于之前通过简单的选择标签切换提升了一点,本节内容使用了一下组件通信实现。
vue+Openlayers加载和切换OSM,高德,谷歌等地图(一)

框架组成

主要是四部分:baseMap.vueLayerSwitcher.vuemapLayer.jsHome.vue

baseMap.vue

<template>
  <div class="map-container">
    <!-- 父传子数据 -->
    <LayerSwitcher
      :layers="layersData"
      :config="mapconfig"
      @layer-change = 'handleLayerChange'
    />
    <div id="map" ref="mapContainer"></div>
  </div>
</template>

<script>
import { layersData, mapconfig } from '@/api/mapLayers'
import { Map, View } from 'ol'
import LayerSwitcher from './LayerSwitcher.vue'
import { fromLonLat } from 'ol/proj'

export default {
  name: 'baseMap',
  components: { LayerSwitcher },
  data () {
    return {
      map: null,
      layersData,
      mapconfig
    }
  },
  mounted () {
    this.initMap()
  },
  methods: {
    initMap () {
      this.map = new Map({
        target: this.$refs.mapContainer,
        layers: layersData,
        view: new View({
          projection: 'EPSG:4326',
          center: fromLonLat([114.3, 30.5]),
          zoom: 8,
          maxZoom: 18
        })
      })
    },
    handleLayerChange (layerId) {
      console.log('Switching to layer:', layerId)
      this.layersData.forEach(layer => {
        console.log('Checking layer:', layer.get('key'), layerId)
        layer.setVisible(layer.get('key') === layerId)
      })
    }
  }
}
</script>

<style lang="less" scoped>
  .map-container {
    position: relative;
    width: 100%;
    height: 100vh;
  }
  #map {
    width: 100%;
    height: 100%;
  }
</style>

图层切换:LayerSwitcher.vue

<template>
  <div class="map_switch" @mouseover="isExpend = true" @mouseout="isExpend = false">
    <div
      class="map_switch_item"
      v-for="item in config"
      :key="item.layer_id"
      :class="{ active: activeLayer === item.layer_id }"
      @click="switchLayer(item.layer_id)"
    >
      <div class="hoverType">
        <div :class="item.className"></div>
        <div class="map_dom">{{ item.label }}</div>
      </div>
    </div>
  </div>
</template>

<script>

export default {
  name: 'LayerSwitcher',
  props: {
    config: Array,
    layers: Array
  },
  data () {
    return {
      activeLayer: 'osmLayer',
      isExpend: false
    }
  },
  methods: {
    switchLayer (layerId) {
      this.activeLayer = layerId
      // 通知父组件切换图层
      this.$emit('layer-change', layerId)
    }
  }
}
</script>

<style lang="less" scoped>
.map_switch {
  position: absolute;
  right: 50px;
  top: 15px;
  z-index: 999;
  display: flex;
  gap: 8px;
  overflow-x: auto;
  background: transparent;
  text-shadow: 0 1px 2px rgba(0, 0, 0, 0.3);
}

.map_switch:hover {
  width: auto;
  overflow: visible;
}

.map_switch_item {
  min-width: 58px;
  padding: 0 8px;
  flex-shrink: 0;
  border: 1px solid rgba(0, 0, 0, 0.1);
  background: rgba(255, 255, 255, 0.3);
  backdrop-filter: blur(4px);
  transition: all 0.3s;

  &.active {
    background: rgba(255, 255, 255, 0.8);
    border-color: #0078d4;
  }
}

.map_switch:not(:hover) .map_switch_item:not(.active) {
  display: none;
}

.hoverType {
  width: 100%;
  padding: 0;
  margin: 0;
  display: flex;
  flex-direction: column;
  align-items: center;
}

.vecType {
  width: 100%;
  height: 38px;
  background: url(../assets/indexImage.jpg) no-repeat -154px -202px;
}

.imgType {
  width: 100%;
  height: 38px;
  background: url(../assets/indexImage.jpg) no-repeat -154px -202px;
}

.map_bom {
  height: 22px;
  line-height: 12px;
  color: #333333;
  white-space: nowrap;
  font-size: 10px;
  font-weight: 300;
  letter-spacing: 0.5px;
}
</style>

存放数据:mapLayer.js

import TileLayer from 'ol/layer/Tile'
import XYZ from 'ol/source/XYZ'

// OSM
const osmLayer = new TileLayer({
  visible: true,
  key: 'osmLayer',
  source: new XYZ({
    url: 'https://tile.openstreetmap.org/{z}/{x}/{y}.png'
  })
})

// Arcgis
const arcgisImgLayer = new TileLayer({
  visible: false,
  key: 'arcgisImgLayer',
  source: new XYZ({
    url: 'https://server.arcgisonline.com/ArcGIS/rest/services/World_Imagery/MapServer/tile/{z}/{y}/{x}',
    crossOrigin: 'anonymous'
  })
})

// 高德
const gaodeImgLayer = new TileLayer({
  visible: false,
  key: 'gaodeImgLayer',
  source: new XYZ({
    url: 'https://wprd0{1-4}.is.autonavi.com/appmaptile?lang=zh_cn&size=1&style=7&x={x}&y={y}&z={z}',
    crossOrigin: 'anonymous'
  })
})

// 谷歌
const googleImgLayer = new TileLayer({
  visible: false,
  key: 'googleImgLayer',
  source: new XYZ({
    url: 'http://mt{0-3}.google.com/vt/lyrs=m&x={x}&y={y}&z={z}',
    crossOrigin: 'anonymous'
  })
})

// 图层组
const layersData = [
  osmLayer,
  arcgisImgLayer,
  gaodeImgLayer,
  googleImgLayer
]

const mapconfig = [
  { layer_id: 'osmLayer', label: 'OSM影像', className: 'imgType' },
  { layer_id: 'arcgisImgLayer', label: 'ersi影像', className: 'imgType' },
  { layer_id: 'gaodeImgLayer', label: '高德街道', className: 'vecType' },
  { layer_id: 'googleImgLayer', label: '谷歌影像', className: 'imgType' }
]

export { layersData, mapconfig }

Home.vue

<template>
  <BaseMap/>
</template>

<script>
import BaseMap from '@/components/baseMap.vue'

export default {
  name: 'HomePage',
  components: { BaseMap }
}

</script>

<style scoped>

</style>

小结

css样式写的可能不太好,大家可以尝试改动。

<think>好的,我现在需要在Vue3项目中使用OpenLayers实现地图图层的动态切换。根据用户提供的引用内容,我应该先回顾一下相关的参考资料,然后结合这些资料来构建解决方案。 首先,引用[1]提到了在Vue3中使用elementplus制作图层控件,包括图层切换、显示隐藏和排序。这说明可能需要结合Element UI的组件,比如按钮或下拉菜单来控制图层的状态。同时,引用[2]指出OpenLayers支持多种地图来源,并且可以叠加图层。这提示我需要创建多个图层,并管理它们的显示和隐藏。 接下来,引用[4]展示了如何将多个图层添加到组内,例如亚洲图层和中国图层,并通过组来管理。这可能是关键步骤,因为图层组可以方便地控制一组图层的可见性。例如,创建不同的图层组,然后通过切换组的可见性来实现动态切换。 然后,引用[3]讨论了右键菜单功能的实现,其中可能涉及事件处理和图层操作。虽然动态切换图层可能不需要右键菜单,但事件处理的经验可能有帮助,比如在点击按钮时触发图层切换的函数。 步骤可能包括: 1. 安装必要的库,如OpenLayers和可能的UI组件库(element-plus)。 2. 创建多个图层实例,可能是不同的地图来源或自定义图层。 3. 将图层组织成图层组,便于管理。 4.Vue组件中创建控制UI,如按钮或开关,绑定到图层的可见性属性。 5. 编写方法,当用户操作UI时,切换相应图层的可见性。 需要注意的地方: - OpenLayers的图层实例需要正确初始化,并添加到地图对象中。 - 动态切换可能需要使用Vue的响应式数据来同步图层状态。 - 图层组的应用可能简化多个图层的管理,但需要确认是否每个图层都需要单独控制还是分组控制更合适。 可能的问题: - 如何确保图层在切换时不会重复添加或移除? - 如何处理图层的顺序(zIndex)以确保正确的显示层级? - 如何优化性能,特别是当图层数量较多时? 需要查阅OpenLayers的文档,确认图层组的使用方法以及如何设置图层的可见性。此外,参考示例中的代码结构,比如如何创建图层组并添加到地图中,然后将图层的visible属性与UI控件绑定。 综合以上思考,步骤应分为环境搭建、图层创建、图层组管理、UI控件绑定和切换逻辑实现几个部分。确保每一步都正确无误,并进行测试验证效果。</think>在Vue3中通过OpenLayers实现地图图层的动态切换,可以按照以下步骤操作: --- ### 一、环境搭建与依赖安装 1. 安装核心库: ```bash npm install ol vue3-openlayers element-plus ``` 2. 引入Element Plus组件库用于构建控制UI[^1] --- ### 、创建图层与图层组 ```typescript // 在Vue组件中定义图层 import { Tile as TileLayer, Group as LayerGroup } from 'ol/layer'; import OSM from 'ol/source/OSM'; import XYZ from 'ol/source/XYZ'; // 基础底图 const osmLayer = new TileLayer({ source: new OSM(), visible: true, title: 'OSM地图' }); // 卫星图 const satelliteLayer = new TileLayer({ source: new XYZ({ url: 'https://server.arcgisonline.com/ArcGIS/rest/services/World_Imagery/MapServer/tile/{z}/{y}/{x}' }), visible: false, title: '卫星图' }); // 创建图层组 const layerGroup = new LayerGroup({ layers: [osmLayer, satelliteLayer] }); ``` --- ### 三、地图初始化 ```html <template> <ol-map ref="map" :layers="layerGroup"> <ol-view :center="[116.4, 39.9]" :zoom="5" /> </ol-map> </template> <script setup> import { ref } from 'vue'; const map = ref(null); </script> ``` --- ### 四、实现切换控制逻辑 1. **添加UI控件**(使用Element Plus): ```html <el-radio-group v-model="activeLayer"> <el-radio-button label="osm">OSM地图</el-radio-button> <el-radio-button label="satellite">卫星图</el-radio-button> </el-radio-group> ``` 2. **响应式数据绑定**: ```typescript const activeLayer = ref('osm'); watch(activeLayer, (newVal) => { layerGroup.getLayers().forEach(layer => { const title = layer.get('title'); layer.setVisible( (newVal === 'osm' && title === 'OSM地图') || (newVal === 'satellite' && title === '卫星图') ); }); }); ``` --- ### 五、关键原理说明 1. **图层可见性控制**:通过`layer.setVisible()`方法动态修改可见性[^4] 2. **图层组管理**:使用`LayerGroup`统一管理多个相关图层 3. **响应式更新**:Vue3的watch监听器实现UI状态与图层状态同步 --- ### 六、扩展优化建议 1. **添加动画过渡**:在切换时使用`layer.setOpacity()`实现淡入淡出效果 2. **图层排序控制**:通过`layer.setZIndex()`调整显示层级 3. **动态加载图层**:使用WMS或GeoJSON源实现按需加载 ```typescript // 示例:动态添加行政区划图层 const addBoundaryLayer = () => { const vectorLayer = new VectorLayer({ source: new VectorSource({ url: '/data/boundary.geojson', format: new GeoJSON() }) }); layerGroup.getLayers().push(vectorLayer); }; ``` ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值