【问题标题】:Click link inside Leaflet Popup and do Javascript单击 Leaflet Popup 中的链接并执行 Javascript
【发布时间】:2012-11-21 20:19:40
【问题描述】:

我有一张传单地图正在运行。它在地图上覆盖了一系列多边形(通过 GeoJSON)并将弹出窗口附加到每个多边形。每个弹出窗口都显示有关该多边形的信息。

我想在弹出窗口中添加一个链接,单击该链接时会运行一个 javascript 函数,该函数通过 AJAX 拉出更小的多边形并显示它们。

我无法让脚本通过正常的 jQuery/Javascript 点击事件捕获对链接的点击。这就是我所说的正常(以下不起作用):

$('a .smallPolygonLink').click(function(e){
  console.log("One of the many Small Polygon Links was clicked");
});

bindPopup 部分如下。它在制作时在每个多边形上运行,并在单击多边形时正确弹出。它确实显示了链接,只是不会在点击时运行上述代码。

var popupContent = "Basic Information..." + '<a class="smallPolygonLink" href="#">Click here to see the smaller polygons</a>';
layer.bindPopup(popupContent);

这里有一个 JSFiddle 来说明这个例子,虽然形式要简单得多。 http://jsfiddle.net/2XfVc/4/

【问题讨论】:

    标签: javascript jquery leaflet


    【解决方案1】:

    这就是我在 mapbox 官方网站上找到的:Create a click event in a marker popup with Mapbox.js and jQuery. 该评论解释了为什么我们使用$('#map') 而不是$('#mybutton')

    var marker = L.marker([43.6475, -79.3838], {
      icon: L.mapbox.marker.icon({
        'marker-color': '#9c89cc'
      })
    })
    .bindPopup('<button class="trigger">Say hi</button>')
    .addTo(map);
    //The HTML we put in bindPopup doesn't exist yet, so we can't just say
    //$('#mybutton'). Instead, we listen for click events on the map element which will bubble up from the tooltip, once it's created and someone clicks on it.
    
    $('#map').on('click', '.trigger', function() {
    alert('Hello from Toronto!');});
    

    【讨论】:

      【解决方案2】:

      每次打开弹出窗口时,弹出窗口内的链接元素都会从您的标记中动态生成。这意味着当您尝试将处理程序绑定到它时,该链接不存在。

      这里的理想方法是使用on 将事件处理委托给弹出元素或其祖先。不幸的是,弹出窗口阻止了事件传播,这就是为什么将事件处理委派给弹出窗口之外的任何静态元素都行不通的原因。

      您可以做的是预先构建链接,附加处理程序,然后将其传递给bindPopup 方法。

      var link = $('<a href="#" class="speciallink">TestLink</a>').click(function() {
          alert("test");
      })[0];
      marker.bindPopup(link);
      

      这是一个演示:http://jsfiddle.net/2XfVc/7/

      一般来说,要使用多个事件处理程序插入任何类型的复杂标记,请使用以下方法:

      // Create an element to hold all your text and markup
      var container = $('<div />');
      
      // Delegate all event handling for the container itself and its contents to the container
      container.on('click', '.smallPolygonLink', function() {
          ...
      });
      
      // Insert whatever you want into the container, using whichever approach you prefer
      container.html("This is a link: <a href='#' class='smallPolygonLink'>Click me</a>.");
      container.append($('<span class="bold">').text(" :)"))
      
      // Insert the container into the popup
      marker.bindPopup(container[0]);
      

      这是一个演示:http://jsfiddle.net/8Lnt4/

      有关在传单弹出窗口中传播事件的更多信息,请参阅 this Git issue

      【讨论】:

      • 如何修改它以添加不可点击的文本或内容?例如。姓名:xxxx,年龄:xxxx,点击链接了解更多详情。只有“链接”这个词是可点击的。另外, [0] 部分有什么作用?我在 jquery click api 中找不到任何参考。
      • @Josh 只需添加其他元素以及可点击的元素。这是一个演示:jsfiddle.net/2XfVc/8 [0] 部分只是从 jQuery 集合中获取 DOM 节点,因为 Leaflet 接受标准 DOM 节点但不接受 jQuery 集合。
      • 太棒了。我将其更改为 .html() 而不是 .text() 以便显示一些 html 格式,但除此之外那是完美的。谢谢。
      【解决方案3】:

      mapbox JavaScript 库有一个事件:

      bindPopup('<button class="trigger">Say hi</button>');
      addTo(map);
      
      $('#map').on('click', '.trigger', function() {
          alert('Hello from Toronto!');
      });
      

      https://www.mapbox.com/mapbox.js/example/v1.0.0/clicks-in-popups/

      【讨论】:

      • 不要转储代码,解释一下。一个好的解释对于理解为什么您提出的解决方案将解决 OP 的问题非常重要。
      【解决方案4】:

      您可以查看popup对象的内部属性,包括_wrapper等。

      map.on('popupopen', _bindPopupClick);
      map.on('popupclose', _unbindPopupClick);
      
      var _bindPopupClick = function (e) {
          if (e.popup) {
              e.popup._wrapper.addEventListener('click', _bindPopupClickHandler);
          }
      };
      var _unbindPopupClick = function (e) {
          if (e.popup) {
              e.popup._wrapper.removeEventListener('click', _bindPopupClickHandler);
          }
      }`
      

      【讨论】:

      • 这个原版解决方案在使用 Vue2 并且您不想使用 jquery 时就像一个魅力。谢谢!
      【解决方案5】:

      我遇到了这个问题,尝试了上面的解决方案。但这对我没有用。找到了以下非常基本的 jquery 解决方案。

      // add your marker to the map
      var my_marker = new L.marker([51.2323, 4.1231], {icon: my_icon});
      var popup = L.popup().setContent('<a class="click" href="#">click</a>');
      my_marker.addTo(map).bindPopup(popup);
      
      // later on
      jQuery("body").on('click','a.click', function(e){
        e.preventDefault();
        alert('clicked');
      });
      

      【讨论】:

        【解决方案6】:

        虽然弹出内容包装器阻止了事件传播,但弹出内部标记中的事件传播得很好。当弹出元素显示在地图上时(并且已成为 DOM 的一部分),您可以将事件添加到弹出元素。敬请关注传单活动popupopen

        var map = L.map('map').setView([51.505, 10], 7); //for example
        
        //the .on() here is part of leaflet
        map.on('popupopen', function() {  
          $('a .smallPolygonLink').click(function(e){
            console.log("One of the many Small Polygon Links was clicked");
          });
        });
        

        http://jsfiddle.net/tJGQ7/2/

        这对我来说就像一个魅力。如果您的弹出窗口没有'a .smallPolygonLink',则上面的代码什么也不做。 此代码在弹出窗口的每次启动时运行。但是您不必担心它会为一个元素附加多个处理程序,因为当弹出窗口关闭时,DOM 节点会被丢弃。

        有一种更通用的方法可以做到这一点。但是,它涉及eval()使用风险自负。但是当 AJAX 加载包含 JS 的部分页面时,您会遇到相同的风险,因此为了启发您,我提出“在您的传单弹出窗口中执行 JS”:

        map.on('popupopen', function(){
            var cont = document.getElementsByClassName('leaflet-popup-content')[0];    
            var lst = cont.getElementsByTagName('script');
            for (var i=0; i<lst.length;i++) {
               eval(lst[i].innerText)
            }
        });
        

        演示:http://jsfiddle.net/tJGQ7/4/

        现在你可以写了:

        var popup_content = 'Testing the Link: <a href="#" class="speciallink">TestLink</a><script> $(".speciallink").on("click", function(){alert("hello from inside the popup")});</script>';
        
        marker.bindPopup(popup_content);
        

        【讨论】:

        • 这里绝对是最好的答案 - 不需要变通办法:-)
        • 是的,应该是这里的最佳答案。很好的解决方案!
        • 这样做的问题是每次打开弹出窗口时您都在重新附加事件处理程序,这现在效率低下,并且一旦您考虑使用多个处理程序插入更复杂的结构就无法使用.这里的理想方法是将事件处理委托给弹出元素或其祖先,这是我最初在回答中建议的。然而,我发现传单会破坏事件传播,这意味着 on 不起作用。第二种最佳方法是将所有事件处理功能精确一次绑定到容器元素并插入。
        • 我处理非常复杂的加载 ajax 的弹出内容,根据我的经验,没有计算周期或内存瓶颈可以证明这里的低效率是合理的。相反,在我的方法中,我将一起属于一个单元的内容和功能分开。您的解决方法 jquery 技巧使容器对象成为一大袋功能,以节省几毫秒的执行时间。我引用:“过早的优化是万恶之源”。
        • 这个答案有效......但会将多个处理程序附加到弹出窗口......请参阅@AsadSaeeduddin 的答案以获得更准确的解决方案。
        【解决方案7】:

        您可以使用 jQuery 来选择 canvas 元素,但您必须在画布中使用它自己的方法。 https://developer.mozilla.org/en/canvas_tutorial 是一个不错的开始。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2019-01-05
          • 1970-01-01
          • 1970-01-01
          • 2017-07-23
          • 2014-06-10
          • 2010-12-09
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多