HTML - 单击按钮导致列表滚动到顶部,原因不明

HTML - Click on button causes list to scroll on top for unknown reasons

我正在使用 tampermonkey 将一些自定义按钮添加到 Unity Documentation

如果我使用 html <button>,我注意到一个奇怪的问题。每次单击按钮时,滚动列表都会滚动到顶部,代码仅在第二次单击时执行。


但是,如果我将 <button> 替换为 <div> 那么一切正常。


为什么 <button> 表现得如此奇怪?

下面是tampermonkey复制脚本

// ==UserScript==
// @name         Unity Documentation (bugtest)
// @namespace    https://docs.unity3d.com
// @version      1.0
// @description  test
// @author       Edward Black
// @match        *://docs.unity3d.com/*
// @grant        GM_addStyle
// ==/UserScript==

GM_addStyle('.confirmBox { z-index: 100; width: 275px; background-color: greenyellow; border: 1px solid black; }');
GM_addStyle('.confirmBoxButtons { margin-top: 5px; }');
GM_addStyle('.confirmBoxClose { position: absolute; height: 20px; width: 20px; background-color: white; color:black; border: 0.5px solid black; text-align: center; right: 0px; }');
GM_addStyle('.confirmBoxClose:hover { background-color: black; color:white; cursor: pointer; }');
GM_addStyle('.confirmBoxBtn { background-color: white; color:black; width: 100px; border: 1px solid black; }');
GM_addStyle('.confirmBoxBtn:hover { background-color: black; color:white; cursor: pointer; }');

$(document).ready(function() {

    setTimeout(function() {
        prepareCustomContextMenue();
        $("div.mCSB_container").delegate("#theButton", "click", function() {
            alert("Hello from Button");
        });
        $("div.mCSB_container").delegate("#theDiv", "click", function() {
            alert("Hello from Div");
        });
        $("div.mCSB_container").delegate(".confirmBoxClose", "click", function() {
            $(".confirmBox").remove();
        });

    }, 4000);


});

function prepareCustomContextMenue()
{
    $("div.mCSB_container").find("a").each(function(j, obj) {

        $(obj).on("contextmenu", function(){
            return false;
        });
        $(obj).on("mousedown", function(e){
            if( e.button == 2 ) {

                console.log('Right mouse button!');
                showConfirmBox(this);

                return false;
            }
            return true;
        });
    });
}

function showConfirmBox(container)
{
    $(".confirmBox").remove();

    var elm = '<li><div class="confirmBox">'+
                  '<div class="confirmBoxClose">x</div>' +

                  '<div class="confirmBoxButtons">' +
                      '<button id="theButton" class="confirmBoxBtn"> This is a button </button>' +
                      '<div id="theDiv" class="confirmBoxBtn"> This is a div </div>' +
                  '</div>' +
              '</div></li>';

    $parent = $(container).parent();
    $(elm).appendTo($parent);
}

说明


等到站点完全加载(大约 4 秒,直到站点加载指示器消失)然后 右键单击 左侧滚动列表中的 link,这应该尽可能向下(这样你可以看到点击按钮后列表实际上是向上滚动的)。 现在应该出现一个容器:

现在单击名为 This is a button<button> 并注意滚动列表滚动到顶部并且按钮中的代码未执行(应显示警报)。再次按下按钮,请注意代码现在已执行,并且在警报上按下“确定”后滚动列表再次滚动到顶部。

接下来单击名为 This is a div<div> 并注意一切正常。

按钮默认会提交页面,导致刷新。

<button id="theButton" class="confirmBoxBtn"> This is a button </button>

按钮的默认 "type" 是 "submit",它是自己发布的。将按钮 "type" 更新为 "button"。

<button type="button" id="theButton" class="confirmBoxBtn"> This is a button </button>

从 jQuery 3.0 开始,delagate() 也已被弃用。

的更新
 $("#theButton").on("click", function(e) {
      // remove default of the click
      e.preventDefault();
      // stop propagation
      e.stopPropagation();
     alert("Hello from Button");
 });

该脚本有几个问题,正如 Jim-miraidev 指出的那样,您需要使用 jQuery 的 .on().stopPropagation().preventDefault() .

但这里的优先级问题是 该页面还有其他几个事件在起作用(尤其是 clickmouseup)。用户脚本代码导致页面的 flexbox 滚动状态变得混乱。
(图表 A:滚动仅在触发 showConfirmBox()mousedown 事件后的第一次点击时发生。)

因此,解决此问题的一种简单方法是 捕获所有 3 个(可能)冲突事件

$("div.mCSB_container").on ("click mousedown mouseup", "#theButton", function (zEvent) {
    zEvent.preventDefault ();
    zEvent.stopPropagation ();

    if (zEvent.type == "mousedown") {
        console.log ("Hello from Button");
    }
} );

请注意,浏览器按顺序触发事件:mousedown、mouseup、click。