Rails - 重叠 Openlayers 地图

Rails - Overlapping Openlayers maps

我只是在我的网站上试验 Openlayers 地图。地图功能运行良好,但我无法将地图正确定位到我的页面上。

我需要在搜索结果屏幕中显示地图:每个结果 1 张地图。下面的代码只是为了显示每个结果的基本 bootstrap 卡片。在我添加地图代码之前,这显示正常(例如,每个结果一张卡片,一张在另一张上面,如下面的屏幕截图所示)。根据第二个屏幕截图,使用地图代码后,所有内容都会重叠。

有什么想法吗?谢谢!

Screenshot of results without the map code

Screenshot of results with the map code

      <% @locations.each do |location| %>
        
            <div class="card" style="width: 18rem;">
                  <div id="map" class="map">
                  <script type="text/javascript">
                    var map = new ol.Map({
                      target: 'map',
                      layers: [
                        new ol.layer.Tile({
                          source: new ol.source.OSM()
                        })
                      ],
                          view: new ol.View({
                            center: ol.proj.fromLonLat([-0.479642,52.641882]),
                            zoom: 10
                          })
                    });
                  </script>
                  
              <div class="card-body">
                <h5 class="card-title">Card title</h5>
                <p class="card-text">Some quick example text to build on the card title and make up the bulk of the card's content.</p>
                <a href="#" class="btn btn-primary">Go somewhere</a>
              </div>
            </div>

            </br></br>
      <% end %>

那个观点是纯粹的意大利面条。您缺少两个结束 </div> 标记,并且您正在创建具有相同 ID 属性的多个元素,这会提供无效文档并导致 slop 模式解析。我的建议是开始使用 HTML 验证器并将内容、行为和表示分开,这样可以更轻松地编写高质量代码。

当你有多个具有相同 id 属性的元素时,document.getElementByIddocument.querySelector 通常会 return DOM 中的第一个元素,但我不相信这一点实际上是标准化的,因为它首先被禁止并且结果可能因浏览器而异。

<% @locations.each do |location| %>
  <div class="card">
    <div class="map"></div>
    <div class="card-body">
      <h5 class="card-title">Card title</h5>
      <p class="card-text">Some quick example text to build on the card title and make up the bulk of the card's content.</p>
      <a href="#" class="btn btn-primary">Go somewhere</a>
    </div>
  </div>
<% end %>

当使用 OpenLayers(或 Google 地图或传单)时,您实际上不必为 target map element - thats just done to create simple quickstart examples which don't really make a great starting point if you want to add multiple maps to a page since you have to jump through a bunch of hoops needlessly just to assign unique ids and then pass them to your JavaScript. Instead you can just pass any HTMLElement 对象使用 ID。

现在让我们写一些真正成熟的东西JavaScript:

// place this in your packs (Rails 6) or assets pipeline (older versions) 
// use 'DOMContentLoaded' if you are not using turbolinks
document.addEventListener('turbolinks:load', function(){
  let elements = document.querySelectorAll('.card .map');
  let maps = elements.forEach(function(element){
    new ol.Map({
      target: element,
      layers: [
        new ol.layer.Tile({
          source: new ol.source.OSM()
        })
      ],
      view: new ol.View({
        center: ol.proj.fromLonLat([-0.479642,52.641882]),
        zoom: 10
      })
    });
  });
});

这不是火箭科学。我们在 turbolinks 执行其页面替换魔法时(以及在初始页面加载时)选择元素,然后为与选择器匹配的每个元素初始化地图实例。而且你不会像那个脚本标签可憎的那样为循环的每次迭代发送完全相同的 JavaScript n 次数。

如果您想在 Rails 和您的 JavaScript 之间传递标记位置等数据,请使用 data attributes

<% @locations.each do |location| %>
  <div class="card">
     <%= content_tag :div,
         class: 'map',
         data: {
           lat: location.latitude,
           lon: location.longitude
         }
     %> 
     <div class="card-body">
       <h5 class="card-title">Card title</h5>
       <p class="card-text">Some quick example text to build on the card title and make up the bulk of the card's content.</p>
       <a href="#" class="btn btn-primary">Go somewhere</a>
    </div>
  </div>
<% end %>
document.addEventListener('turbolinks:load', function(){
  let elements = document.querySelectorAll('.card .map');
  let maps = elements.forEach(function(element){
    new ol.Map({
      target: element,
      layers: [
        new ol.layer.Tile({
          source: new ol.source.OSM()
        })
      ],
      view: new ol.View({
        // Map now centers on right location. Magic!
        center: ol.proj.fromLonLat([data.lon, data.lat]),
        zoom: 10
      })
    });
  });
});