Prevent link from opening while clicking and holding to drag in Google Chrome

Asked

Viewed 84 times

3

How to prevent a link from opening while holding and dragging your mouse in Google Chrome?

The script below is to perform scroll action while clicking and dragging, but when it comes to links, when dropping the mouse button the link opens, such as preventing it from opening while dragging, and opening the link only when clicking?

(function(root, factory) {
  if (typeof define === 'function' && define.amd) {
    define(['exports'], factory);
  } else if (typeof exports !== 'undefined') {
    factory(exports);
  } else {
    factory((root.dragscroll = {}));
  }
}(this, function(exports) {
  var _window = window;
  var _document = document;
  var mousemove = 'mousemove';
  var mouseup = 'mouseup';
  var mousedown = 'mousedown';
  var EventListener = 'EventListener';
  var addEventListener = 'add' + EventListener;
  var removeEventListener = 'remove' + EventListener;
  var newScrollX, newScrollY;

  var dragged = [];
  var reset = function(i, el) {
    for (i = 0; i < dragged.length;) {
      el = dragged[i++];
      el = el.container || el;
      el[removeEventListener](mousedown, el.md, 0);
      _window[removeEventListener](mouseup, el.mu, 0);
      _window[removeEventListener](mousemove, el.mm, 0);
    }

    // cloning into array since HTMLCollection is updated dynamically
    dragged = [].slice.call(_document.getElementsByClassName('dragscroll'));
    for (i = 0; i < dragged.length;) {
      (function(el, lastClientX, lastClientY, pushed, scroller, cont) {
        (cont = el.container || el)[addEventListener](
          mousedown,
          cont.md = function(e) {
            if (!el.hasAttribute('nochilddrag') ||
              _document.elementFromPoint(
                e.pageX, e.pageY
              ) == cont
            ) {
              pushed = 1;
              lastClientX = e.clientX;
              lastClientY = e.clientY;

              e.preventDefault();
            }
          }, 0
        );

        _window[addEventListener](
          mouseup, cont.mu = function() {
            pushed = 0;
          }, 0
        );

        _window[addEventListener](
          mousemove,
          cont.mm = function(e) {
            if (pushed) {
              (scroller = el.scroller || el).scrollLeft -=
                newScrollX = (-lastClientX + (lastClientX = e.clientX));
              scroller.scrollTop -=
                newScrollY = (-lastClientY + (lastClientY = e.clientY));
              if (el == _document.body) {
                (scroller = _document.documentElement).scrollLeft -= newScrollX;
                scroller.scrollTop -= newScrollY;
              }
            }
          }, 0
        );
      })(dragged[i++]);
    }
  }


  if (_document.readyState == 'complete') {
    reset();
  } else {
    _window[addEventListener]('load', reset, 0);
  }

  exports.reset = reset;
}));
.dragscroll{
  width:400px;
  overflow:scroll;
}
.dragscroll div{
  width:555px;
}
.dragscroll a{
  display:block;
  width:180px;
  height:100px;
  margin-right:5px;
  float:left;
}
.dragscroll::after {
  content: "";
  clear: both;
  display: table;
}
<div class="dragscroll">
<div>
<a href="https://www.example.com" style="background:#333;"></a>
<a href="https://www.example.com" style="background:#ddd;"></a>
<a href="https://www.example.com" style="background:#dd3333;"></a>
</div>
</div>

3 answers

1


There is an alternative using two events: mousedown and mouseup. When the user clicks on the link and holds for more than 100ms, it will change the variable flag for true, and when releasing, firing the mouseup, will call a function (libera()) that will cancel the event click link. If the event click has been canceled, after 100ms again will call the same function releasing the links to click.

Would look like this:

// variáveis de controle
var flag, tempo;

document.onmouseup = function(){
   if(flag){
      libera(flag);
      setTimeout(function(){
         flag = false;
         libera(flag);
      }, 100)
   }else{
      clearTimeout(tempo);
   }
}

document.onmousedown = function(e){
   var el = e.target;
   // verifica se o que foi clicado é um link <a>
   if(el.tagName == "A"){
      tempo = setTimeout(function(){
         flag = true;
      }, 100);
   }
}

function libera(c){
   var links = document.querySelectorAll(".dragscroll a");
   for(let x = 0; x < links.length; x++){
      links[x].onclick = function(e){
         if(!c) return true; // ação normal do link
         e.preventDefault(); // cancela a ação do link
      }
   }

}


(function(root, factory) {
  if (typeof define === 'function' && define.amd) {
    define(['exports'], factory);
  } else if (typeof exports !== 'undefined') {
    factory(exports);
  } else {
    factory((root.dragscroll = {}));
  }
}(this, function(exports) {
  var _window = window;
  var _document = document;
  var mousemove = 'mousemove';
  var mouseup = 'mouseup';
  var mousedown = 'mousedown';
  var EventListener = 'EventListener';
  var addEventListener = 'add' + EventListener;
  var removeEventListener = 'remove' + EventListener;
  var newScrollX, newScrollY;

  var dragged = [];
  var reset = function(i, el) {
    for (i = 0; i < dragged.length;) {
      el = dragged[i++];
      el = el.container || el;
      el[removeEventListener](mousedown, el.md, 0);
      _window[removeEventListener](mouseup, el.mu, 0);
      _window[removeEventListener](mousemove, el.mm, 0);
    }

    // cloning into array since HTMLCollection is updated dynamically
    dragged = [].slice.call(_document.getElementsByClassName('dragscroll'));
    for (i = 0; i < dragged.length;) {
      (function(el, lastClientX, lastClientY, pushed, scroller, cont) {
        (cont = el.container || el)[addEventListener](
          mousedown,
          cont.md = function(e) {
            if (!el.hasAttribute('nochilddrag') ||
              _document.elementFromPoint(
                e.pageX, e.pageY
              ) == cont
            ) {
              pushed = 1;
              lastClientX = e.clientX;
              lastClientY = e.clientY;

              e.preventDefault();
            }
          }, 0
        );

        _window[addEventListener](
          mouseup, cont.mu = function() {
            pushed = 0;
          }, 0
        );

        _window[addEventListener](
          mousemove,
          cont.mm = function(e) {
            if (pushed) {
              (scroller = el.scroller || el).scrollLeft -=
                newScrollX = (-lastClientX + (lastClientX = e.clientX));
              scroller.scrollTop -=
                newScrollY = (-lastClientY + (lastClientY = e.clientY));
              if (el == _document.body) {
                (scroller = _document.documentElement).scrollLeft -= newScrollX;
                scroller.scrollTop -= newScrollY;
              }
            }
          }, 0
        );
      })(dragged[i++]);
    }
  }


  if (_document.readyState == 'complete') {
    reset();
  } else {
    _window[addEventListener]('load', reset, 0);
  }

  exports.reset = reset;
}));
.dragscroll{
  width:400px;
  overflow:scroll;
}
.dragscroll div{
  width:555px;
}
.dragscroll a{
  display:block;
  width:180px;
  height:100px;
  margin-right:5px;
  float:left;
}
.dragscroll::after {
  content: "";
  clear: both;
  display: table;
}
<div class="dragscroll">
   <div>
      <a href="https://www.example.com" style="background:#333;"></a>
      <a href="https://www.example.com" style="background:#ddd;"></a>
      <a href="https://www.example.com" style="background:#dd3333;"></a>
   </div>
</div>

  • It worked perfectly with a modification, removing the if(el.tagName == "A"), because in my code the el is returned as li and not the a.

  • It may be too :))

1

I’ll be very honest with you, putting time is not so pleasant. You can use join with css, Pointerevents. Ai only if the user does not actually move the click will be available. And it works not only for links but others as well. Obs no matter the time, the click will only be allowed if the user does not move. That’s how uncle google does if I am not mistaken

let dragscroll = document.querySelector('.dragscroll'),
        div = document.querySelector('.dragscroll div'),
        tagA = document.querySelectorAll('.dragscroll div a'),
        mousedown = false;

    window.addEventListener('mouseup', function () {
        mousedown = false;
        tagA.forEach(e => {
            e.style.pointerEvents = 'visible';
            e.style.cursor = 'pointer';
        });
        div.style.cursor = 'grab';
    }, true);

    div.addEventListener('mousedown', function (e) {
        mousedown = true;
        x = div.offsetLeft - e.clientX;
    }, true);
    
    dragscroll.addEventListener('mousemove', function () {
        if (mousedown) {
            div.style.cursor = 'grabbing';
            tagA.forEach(e => {
                e.style.pointerEvents = 'none';
            });
        };
    }, true);
























(function(root, factory) {
  if (typeof define === 'function' && define.amd) {
    define(['exports'], factory);
  } else if (typeof exports !== 'undefined') {
    factory(exports);
  } else {
    factory((root.dragscroll = {}));
  }
}(this, function(exports) {
  var _window = window;
  var _document = document;
  var mousemove = 'mousemove';
  var mouseup = 'mouseup';
  var mousedown = 'mousedown';
  var EventListener = 'EventListener';
  var addEventListener = 'add' + EventListener;
  var removeEventListener = 'remove' + EventListener;
  var newScrollX, newScrollY;

  var dragged = [];
  var reset = function(i, el) {
    for (i = 0; i < dragged.length;) {
      el = dragged[i++];
      el = el.container || el;
      el[removeEventListener](mousedown, el.md, 0);
      _window[removeEventListener](mouseup, el.mu, 0);
      _window[removeEventListener](mousemove, el.mm, 0);
    }

    // cloning into array since HTMLCollection is updated dynamically
    dragged = [].slice.call(_document.getElementsByClassName('dragscroll'));
    for (i = 0; i < dragged.length;) {
      (function(el, lastClientX, lastClientY, pushed, scroller, cont) {
        (cont = el.container || el)[addEventListener](
          mousedown,
          cont.md = function(e) {
            if (!el.hasAttribute('nochilddrag') ||
              _document.elementFromPoint(
                e.pageX, e.pageY
              ) == cont
            ) {
              pushed = 1;
              lastClientX = e.clientX;
              lastClientY = e.clientY;

              e.preventDefault();
            }
          }, 0
        );

        _window[addEventListener](
          mouseup, cont.mu = function() {
            pushed = 0;
          }, 0
        );

        _window[addEventListener](
          mousemove,
          cont.mm = function(e) {
            if (pushed) {
              (scroller = el.scroller || el).scrollLeft -=
                newScrollX = (-lastClientX + (lastClientX = e.clientX));
              scroller.scrollTop -=
                newScrollY = (-lastClientY + (lastClientY = e.clientY));
              if (el == _document.body) {
                (scroller = _document.documentElement).scrollLeft -= newScrollX;
                scroller.scrollTop -= newScrollY;
              }
            }
          }, 0
        );
      })(dragged[i++]);
    }
  }


  if (_document.readyState == 'complete') {
    reset();
  } else {
    _window[addEventListener]('load', reset, 0);
  }

  exports.reset = reset;
}));
.dragscroll{
  width:400px;
  overflow:scroll;
  cursor: grab
}
.dragscroll div{
  width:555px;
}
.dragscroll a{
  display:block;
  width:180px;
  height:100px;
  margin-right:5px;
  float:left;
}
.dragscroll::after {
  content: "";
  clear: both;
  display: table;
}
<div class="dragscroll">
<div>
<a href="https://www.example.com" style="background:#181818;"></a>
<a href="https://www.example.com" style="background:#262626;"></a>
<a href="https://www.example.com" style="background:#444444;"></a>
</div>
</div>

0

You can use the attribute draggable and set it to false. This will prevent the link from being draggable.

<a draggable="false" href="https://answall.com">Seu link</a>

  • I think you do not understand, try to execute the question snippet and drag to understand better... When clicking to drag and drop, the link opens, this is the problem, the link should not be opened if the user drags, it should only be opened if click.

  • am using google Chrome

  • I just checked, this problem only happens on Chrome

Browser other questions tagged

You are not signed in. Login or sign up in order to post.