单击缩放按钮时如何防止 Leaflet 滚动页面?

How to prevent Leaflet from scrolling the page when clicking the zoom buttons?

我在 HTML 页面上有一张传单地图。当页面滚动到地图的任何部分都在视口之外并且我单击缩放按钮时,地图会跳转以便它在视口中完全可见。如果整个地图不适合,则地图的顶部与视口的顶部对齐,而底部刚好悬在末端。

这很烦人,因为用户刚刚按下的缩放按钮不再在光标下,他们必须重新找到它。

我已经尝试了内置缩放栏和我使用 map.setZoom() 的自定义缩放栏,并且行为是一致的。然而,https://leafletjs.com上的示例地图并没有这样做,所以我很茫然。

我的地图很简单:

var home = {center: L.LatLng(51.499725, -0.124695), zoom: 11};
var mymap = L.map('map').setView(home.center, home.zoom);

This question 听起来与我所看到的相似,但比我的情况更复杂。无论如何,没有解决办法。

编辑: 这是 html 和 CSS,但再基本不过了。

map.html

    <div class="container mx-sm-3">
        <div class="row">
            <div class="col">
                <div id="map"></div>
            </div>
        </div>
    </div>

map.css

#map {
    height: 570px;
    width: 700px;
}

罪魁祸首是this line of code:

this._map.getContainer().focus();

背后的原理是什么?地图容器必须具有 focus 以便键盘事件通过它进行路由。单击缩放按钮会将焦点设置在按钮本身上,并使地图在某些情况下出现异常。

但是焦点的一个副作用是焦点 HTML 元素会使用户代理(网络浏览器)将其滚动到视图中,因为假定用户会希望看到焦点元素在对它进行任何键盘输入之前。

有了这些知识,我将以两种不同的方式重新表述您的问题:

I do not need the map element to be focused at all. How do I prevent Leaflet from focusing the map after clicking on the zoom buttons?

_refocusOnMap() private method of L.Control 什么都不做。

这可以通过 monkey-patching 的快速和肮脏的方式完成:

L.Control.prototype._refocusOnMap = function _refocusOnMap() {};

记得在实例化地图之前进行 monkey-patch。基于此,"clean" 将是 L.Control and/or L.Control.Zoomcreate subclasses。如果您有自己的缩放控件,您还可以提供自定义 _refocusOnMap 方法,而不是依赖父 class.

提供的方法

I would like the keyboard controls to keep working, but I do not want to scroll the whole map into view after pressing the zoom buttons. Can the map be focused but skipping the "scroll into view" business?

是的,但要注意。

focus method of HTMLElements 接受一个 options 参数,该参数可以包含 preventScroll 选项。

因此您可以通过以下方式对 _refocusOnMap() 进行猴子修补:

L.Control.prototype._refocusOnMap = function _refocusOnMap(ev) {
    // if map exists and event is not a keyboard event
    if (this._map && ev && ev.screenX > 0 && ev.screenY > 0) {
        this._map.getContainer().focus({ preventScroll: true });
    }
};

但是请注意,support for preventScroll is not present in all browsers

另一种方法是 preventDefault 地图上的 focusfocusin 事件,例如:

L.DomEvent.on(map.getContainer(), 'focus', L.DomEvent.preventDefault)

但是,由于网络浏览器之间的不一致,这可能不仅会停止滚动,还会停止聚焦,或者可能根本没有效果,具体取决于所使用的网络浏览器。

    this._map.getContainer().focus = ()=>{}