如何突出显示在我的传单地图(nuxt/vue)中单击了哪个标记

Posted

技术标签:

【中文标题】如何突出显示在我的传单地图(nuxt/vue)中单击了哪个标记【英文标题】:How can I highlight which marker has been clicked in my leaflet map (nuxt/vue) 【发布时间】:2021-04-23 00:44:19 【问题描述】:

我有一张传单地图,上面显示了一个地区的不同餐厅和远足径。 当用户单击标记时,我会在下面的 div 中显示有关它的信息。

但是,如果当您单击标记时,它会在地图上突出显示自己,这样您就可以准确地看到您当前正在阅读的标记,这将是一个很好的用户体验。

但是我似乎找不到办法。

标记是通过使用 v-for 循环通过“位置”对象的 JSON 文件创建的,JSON 示例:

    "locations": 
            "restaurants": [
                    "id": "R1",
                    "name": "El Rancho Grande",
                    "latlong": [
                        "36.90316216998795",
                        "-4.115129907833307"
                    ],
                    "type": "Restaurant",
                    "description": "This is a description of the location",
                    "img": "https://www.viewranger.com/routelibrary/discoverywalks/axarquia/0115.jpg"
                
...

在我看来,一种方法可能是:

    创建所有标记并添加到数组中。

    将它们全部添加到地图中。

    当一个被点击时,在数组中找到那个标记,更新它的图标以显示它当前被选中。

    删除所有标记。

    用现在更新的标记重新绘制它们。

但是这种方法似乎太过分了,所以我对此表示怀疑。

谁能给我一些想法?干杯!

这是我在“了解该地区”页面中的地图:

   ...
        <!-- ############# INTERACTIVE MAP ############# -->
        <div class="area__map">
          <div id="map-wrap">
            <no-s-s-r>
              <l-map :zoom="13" :center="[36.9023, -4.1139]" ref="map">
                <l-tile-layer
                  url="http://s.tile.osm.org/z/x/y.png"
                ></l-tile-layer>
                <!-- ############# CREATE RESTAURANT MARKERS ############# -->
                <l-marker
                  v-for="restaurant in restaurants"
                  :key="restaurant.id"
                  :lat-lng="restaurant.latlong"
                  :icon="eatIcon"
                  v-on:click="getPin(restaurant.id)"
                ></l-marker>
                <!-- ############# CREATE HIKING TRAIL MARKERS ############# -->
                <l-marker
                  v-for="walk in walks"
                  :key="walk.id"
                  :lat-lng="walk.latlong"
                  :icon="walkIcon"
                  v-on:click="getPin(walk.id)"
                ></l-marker>
              </l-map>
            </no-s-s-r>
          </div>
          <!-- ############# SHOW CURRENT SELECTED MARKER INFO ############# -->
          <div class="area__map__selected-pin">
            <h3> selectedPin.name </h3>
            <h4> selectedPin.type </h4>
            <p> selectedPin.description </p>
            <img
              v-if="selectedPin.img != ''"
              :src="selectedPin.img"
              class="area__map__selected-pin__selected-img"
            />
          </div>
          <div class="area__subheader triangle triangle-yellow"></div>
        </div>
    </template>
    
    <script>
    import json from '@/static/json/locations.json'
    import  latLng, icon  from 'leaflet'
    export default 
      name: 'Area',
      data: function () 
        return 
          // ############# INTRO VIDEO SETTINGS #############
          videoLanguage: 'English',
          englishSrc: 'https://www.youtube.com/embed/lRKmJqDbVsY',
          spanishSrc: 'https://www.youtube.com/embed/q0WkEkIMmQo',
          currentSrc: 'https://www.youtube.com/embed/lRKmJqDbVsY',
          // ############# IMAGE GALLERY SETTINGS #############
          swiperOption: 
            grabCursor: true,
            loop: true,
            autoplay: 
              delay: 5000,
              disableOnInteraction: false,
            ,
            pagination: 
              el: '.swiper-pagination',
            ,
            map: this.$refs.map,
          ,
          // ############# ARRAY TO STORE GALLERY IMAGES #############
          images: [],
          locations: json.locations,
          // ############# ARRAY TO STORE RESTAURANT OBJECTS #############
          restaurants: [],
          // ############# ARRAY TO STORE HIKING TRAIL OBJECTS #############
          walks: [],
          // ############# LEAFLET HIKING TRAIL MARKER ICON #############
          walkIcon: icon(
            iconUrl: '/MapMarkers/hiking.png',
            iconSize: [20, 20],
            iconAnchor: [16, 37],
          ),
          // ############# LEAFLET RESTAURANT MARKER ICON #############
          eatIcon: icon(
            iconUrl: '/MapMarkers/restaurant.png',
            iconSize: [20, 20],
            iconAnchor: [16, 37],
          ),
          // ############# STORE THE CURRENTLY SELECTED LOCATION DATA  #############
          selectedPin: 
            name: 'Please click on a map pin for more information',
          ,
        
      ,
      // ############# IMPORT THE IMAGES ON MOUNT #############
      mounted() 
        this.importImages(require.context('~/assets/AreaPictures/', true))
        this.importLocations(this.locations)
        console.log(this.fas)
      ,
      methods: 
        changeSrc() 
          if (this.videoLanguage === 'English') 
            this.currentSrc = this.englishSrc
           else 
            this.currentSrc = this.spanishSrc
          
        ,
        // ############# IMPORT GALLERY IMAGES #############
        importImages(r) 
          r.keys().forEach((key) => 
            var path = key.substring(1) //-----THE PATH FOR SOME REASON CONTAINS A . SO I REMOVE IT
            this.images.push(
              imageURL: path, //----- CREATE A NEW OBJECT AND ADD IT TO IMAGES
            )
          )
        ,
        // ############# SPLIT JSON DATA INTO RESTAURANT AND HIKING TRAIL ARRAYS #############
        importLocations() 
          this.restaurants = this.locations.restaurants
          this.walks = this.locations.walks
        ,
        // ############# FIND THE DATA OF THE CURRENTLY SELECTED MAP MARKER BY USING ITS ID #############
        getPin(id) 
          let item
          if (id.includes('W')) 
            for (let i = 0; i < this.walks.length; i++) 
              item = this.walks[i]
              if (item.id === id) 
                this.selectedPin = item
              
            
           else if (id.includes('R')) 
            for (let i = 0; i < this.restaurants.length; i++) 
              item = this.restaurants[i]
              if (item.id === id) 
                this.selectedPin = item
              
            
           else 
            window.alert('Error, no info on marker found')
          
        ,
      ,
    
    </script>
    
    <style lang="scss">
    ...

编辑: 上下文图片

【问题讨论】:

【参考方案1】:

我的建议是:

当一个标记被选中时,给 html 元素添加一个类,它会添加一个投影,并缩放图标:

.markerSelected 
  transform: scale(1.5);
  filter: drop-shadow(0px 0px 10px rgba(0,0,0,.5));

另外,为了捕获事件,我建议使用事件冒泡。为此,请将您的@click 添加到父元素,然后使用event.target 找到单击的图标。

一旦您发出了事件,请将 selectedId 数据参数设置为所选项目的 ID。我在这里假设walking vs restaurant id 是独一无二的,不会有冲突。

然后,按如下方式更新 HTML:

<l-marker
                  v-for="restaurant in restaurants"
                  :key="restaurant.id"
                  :lat-lng="restaurant.latlong"
                  :icon="eatIcon"
                  :class="restaurant.id === selectedId ? 'markerSelected' : ''"
                ></l-marker>

阅读:Event.Target

这里还有另一个好帖子:How to bubble events in vue

【讨论】:

非常感谢您的回复。所以根据我的理解,你推荐使用 $emit?它将向父级发送事件。 我已经实现了这个,我可以从标记调用一个函数到父级,但是我对如何将该类添加到标记感到困惑。另外,如果用户单击另一个标记,我如何将其从标记中删除并将其添加到另一个标记中 您可以向l-marker 添加一个响应式类。我已经添加到上面的回复中

以上是关于如何突出显示在我的传单地图(nuxt/vue)中单击了哪个标记的主要内容,如果未能解决你的问题,请参考以下文章

如何使用传单和 jQuery Birdseye 在点击时突出显示标记

如何获取传单 WMS 地图的最近特征?

反应传单地图未正确显示

反应传单地图未正确显示

突出显示由选择项指向的 R 传单多边形(不单击它)

为传单中的标记分配 ID