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

我只是一个虾纸丫 提交于 2019-12-12 18:29:25

问题


I am using tampermonkey to add some custom buttons to the Unity Documentation.

I noticed a strange problem If I am using a html <button>. Everytime when I click on the button, then the scroll list is scrolling to the top and the code is only executed on the second click.


However, If I replace <button> with <div> then everything is working perfectly fine.


Why is <button> behaving so weird?

Below is the tampermonkey script for reproduction.

// ==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);
}

Instructions


Wait until the site loaded completly (about 4 seconds until the site load indicator disapeared) then right click on a link in the scroll list at left, which should be as far as possible down (so you can see that the list is actually scrolling up after clicking on the button). Now a container should appear:

Now click on the <button> named This is a button and notice that the scroll list scrolls to the top and the code from the button is not executed (alert should show). Press again on the button and notice that the code is now executed and the scroll list scrolls to top again after pressing Ok on the alert.

Next click on the <div> named This is a div and note that everything works as expected.


回答1:


There are several issues with that script and, as Jim-miraidev pointed out, you need to use jQuery's .on(), .stopPropagation(), and .preventDefault().

But the priority problem here is that the page has several other events at play (especially click and mouseup). The userscript code is causing the page's flexbox scroll state to get confused.
(Exhibit A: the scroll only happens on first click immediately after the mousedown event that fires showConfirmBox().)

So, an easy way to patch this is to capture all 3 of the (potentially) conflicting events:

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

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

Note that browsers fire the events in the order: mousedown, mouseup, click.




回答2:


Buttons default will submit the page, causing a refresh.

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

The default "type" for a button is "submit", which self posts. Update the button "type" to "button".

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

Also delagate() as of jQuery 3.0, has been deprecated. Update for

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


来源:https://stackoverflow.com/questions/47392322/html-click-on-button-causes-list-to-scroll-on-top-for-unknown-reasons

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!