【问题标题】:Capture mouse wheel event as native HTML attribute将鼠标滚轮事件捕获为原生 HTML 属性
【发布时间】:2017-05-15 17:39:45
【问题描述】:

我即将开始使用鼠标滚轮事件,但我能在网上找到的唯一方法是使用 addEventListener()。我想检测的是原生 HTML 和 CSS。换句话说,我正在寻找类似的东西:

<span id='fooBar' onmousewheel='alert("fooBar")'></span>

我正在动态创建跨度并将它们注入到 DOM 中,如果我不必运行 javascript 来执行此操作,它会工作得更好。我似乎可以在本地工作但不是鼠标滚轮的所有其他事件。这可能吗?

【问题讨论】:

    标签: javascript html css mousewheel


    【解决方案1】:

    您只找到对 addEventListener() 的引用的原因是因为这是 standard 和正确的方法(似乎 Firefox 甚至不支持 onmousewheel) .

    虽然可以使用您在问题中显示的代码(在支持它的浏览器中)使用您在问题中显示的代码(除了您的 span 是空的,因此您无法使用它启动事件,因为元素不会有任何渲染大小),我有一个下面的例子,使用内联 HTML 事件处理属性可以追溯到我们有标准之前的时间,不应该使用。 Here's a link 我的另一个答案解释了原因。

    &lt;span id='fooBar' onmousewheel='alert("fooBar")'&gt;Use the mousewheel while mouse is over this&lt;/span&gt;

    【讨论】:

    • 好吧,至于空的 只是为了举例说明我正在寻找什么格式。我的实际元素确实有内容。
    【解决方案2】:

    内联与委托

    在演示中,A 端使用标准的addEventListener 并注册wheel 事件,该事件替代了已弃用的mousewheel 事件。使用addEventListener 不仅是标准,而且如果使用event delegation,它是最有效的。

    使用onwheel 作为属性事件的支持有限,因为使用任何属性事件都是非标准且不鼓励的。尽管如此,我还是包含了 B 面,它使用已弃用的非标准 onmousewheel 事件作为属性内联事件处理程序。因为它是一个笨拙的编码&lt;span&gt;,所以我在一个使用所有三个引号(即'"、`)的字符串上使用了insertAdjacentHTML。在第二层嵌套引号中使用了字符串文字,非常混乱。

    请参阅此post,了解如何在事件委托中使用事件对象属性。

    详情在demo中注释

    演示

    // Reference the buttons 
    const btnA = document.getElementById('addA');
    const btnB = document.getElementById('addB');
    
    // Reference the parent nodes
    const secA = document.querySelector('section:first-of-type');
    const secB = document.querySelector('section:last-of-type');
    
    // Register the click event on buttons
    btnA.addEventListener('click', addNodeA, false);
    btnB.addEventListener('click', addNodeB, false);
    
    /* Register the wheel event on section A 
    || which is the parent node of the wheeled
    || nodes. Event delegation involves one 
    || event handler for multiple event targets.
    || This is far more efficient than multiple 
    || inline event handlers.
    */
    secA.addEventListener('wheel', markNode, false);
    
    let cnt = 0;
    
    /* Add node A to section A
    || ex. <span id="A1" class="A">A1</span>
    */
    function addNodeA(e) {
      cnt++;
      var nodeA = document.createElement('span');
      nodeA.id = 'A' + cnt;
      nodeA.textContent = nodeA.id;
      nodeA.className = 'A';
      secA.appendChild(nodeA);
      return false;
    }
    
    /* Add node B to section B
    || ex. <span id="B3" class="B" onmousewheel="this.style.outline = `5px dashed red`">B3</span>
    */
    function addNodeB(e) {
      cnt++;
      /* This string is wrapped in single quotes,
      || double quotes for the attributes values,
      || and backticks for the property value of
      || an attribute value. Very messy, confusing,
      || and inefficient.
      */
      var nodeB = '<span id="B' + cnt + '" class="B" onmousewheel="this.style.outline = `5px dashed red`">B' + cnt + '</span>';
    
      // insertAdjacentHTML is innerHTML on steroids
      secB.insertAdjacentHTML('beforeend', nodeB);
      return false;
    }
    
    function markNode(e) {
    
      /* If the wheeled node (i.e. e.target) is not the 
      || registered node (i.e. e.currentTarget), then...
      */
      if (e.target !== e.currentTarget) {
        var node = e.target;
        if (node.className === 'A') {
          node.style.outline = '5px dashed blue';
        } else {
          return false;
        }
      }
    }
    html,
    body {
      width: 100%;
      width: 100%
    }
    
    fieldset {
      height: 10%;
    }
    
    main {
      border: 3px solid lime;
      height: 90%;
      min-height: 250px;
      display: flex;
    }
    
    section {
      width: 50%;
      min-height: 250px;
      outline: 3px dashed gold;
      padding: 10px 25px;
    }
    
    span {
      height: 50px;
      width: 50px;
      padding: 2px;
      text-align: center;
      font-size: 12px;
      margin: 5px;
      display: inline-block;
    }
    
    .A {
      background: rgba(0, 100, 200, .3);
    }
    
    .B {
      background: rgba(200, 100, 0, .3);
    }
    
    #addB {
      margin-left: 35%
    }
    <fieldset>
      <legend>addNode</legend>
      <button id='addA'>nodeA</button>
      <button id='addB'>nodeB</button>
    </fieldset>
    <main>
      <section></section>
      <section></section>
    </main>

    【讨论】:

    • 我想这确实引发了另一个问题。我进行内联事件处理的主要原因是因为我将元素添加到 DOM 中的方式。当我创建有问题的元素时,它实际上是一组 4 个嵌套元素。您的 A 编码示例每个元素需要 4 行左右,压缩它们会使编码变得相当难看。我使用更像 B 的东西,所以它每行大约 2 行,并且很容易阅读 HTML。这只是被认为是一种不好的方式吗?我试图保持我的代码简短易读(它已经达到了成千上万的总数)
    • 事件委托成本是预先确定的,只有一个eventListener 涵盖多个元素。 1000 多个元素的内联是 1000 多个事件处理程序。 1000 多个元素的事件委托是 1 个事件处理程序。
    • 代码可能可以重构以提高可读性或简洁性,我为演示编写的模式是两者的混合,因此重要部分很清楚,并且很容易遵循到达那里的步骤。在大多数情况下,添加 id、class 等的额外步骤实际上是不必要的。有 4 个嵌套元素,使它们像 B 更好,但是仍然可以应用来自 A 的事件委托,除非这些集群都不共享一个共同的祖先(可能是单独的文档?)
    • 抱歉,我的意思是成千上万行代码。我确实需要大多数元素的类。我可以将两者混合使用,如果不应该为任何事件内联完成,它只会为事件侦听器添加相当多的编码。
    • 你必须选择你的战斗,我知道这是怎么回事。您的集群是相同的标签和布局还是不同?如果您的集群具有相同的标签和布局,您可以使用 &lt;template&gt;documentFragment 作为补充或替代方法。
    【解决方案3】:

    您可以很容易地使用侦听器动态创建元素。您只需要了解 DOM 以及如何附加事件侦听器。

    下面的示例创建了 10 个跨度并为每个跨度附加了一个侦听器。只需将鼠标悬停在一个跨度上并滚动鼠标滚轮。跨度的 ID 将记录到控制台。

    // Create 10 spans with a scroll listener.
    var count = 10;
    for (var i = 0; i < count; i++) {
      var span = document.createElement('SPAN');
      span.id = 'foo-bar-' + i;
      span.innerHTML = 'Foo #' + i;
      addEventListener(span, 'mousewheel', performEvent);
      document.body.appendChild(span);
    }
    
    // Event function.
    function performEvent(e) {
      console.log(e.target.id);
    }
    
    // IE 8+ via http://youmightnotneedjquery.com/
    function addEventListener(el, eventName, handler) {
      if (el.addEventListener) {
        el.addEventListener(eventName, handler);
      } else {
        el.attachEvent('on' + eventName, function(){
          handler.call(el);
        });
      }
    }
    .as-console-wrapper { max-height: 5em !important; }
    
    span[id^="foo-bar-"] {
      border: thin solid black;
      margin: 0.25em;
    }

    【讨论】:

    • addEventListener() 代理/包装器将在您向其传递 IE DOMContentLoaded。
    • @ScottMarcus 我知道,但没有人应该使用低于 IE 8 的版本。这是一种安全风险。此外,IE 8 早在 8 年前就问世了。在互联网世界,这相当于一千年。
    • 这正是我的观点。为什么还要显示 IE 8 补丁? .addEventListener() 被所有主流浏览器支持至少 5 年。您的代码可能会失败,只会促进过时软件的继续使用。根本没有人应该使用 IE 8。
    • @ScottMarcus 因为许多主要的 Web 应用程序仍然支持 IE。这是最后一个至少“可以忍受”的 IE 版本。
    • 我们将不得不同意在这里不同意。实际统计数据不支持该声明。当然,总会有例外,但美国企业(以及世界其他地区)大肆迁移了这些应用程序。多年前。大多数人会告诉你,IE 9 绝对是应该被容忍的 IE 最早版本。
    【解决方案4】:

    尝试以下方法:

    ::-webkit-scrollbar {
        width: 0px;  /* remove scrollbar space */
        background: transparent;  /* optional: just make scrollbar invisible */
    }
    <!DOCTYPE HTML>
    <html>
      <body style="overflow: auto;
    max-height: 100vh;" onscroll="alert('hi')">
        <div style="height:2000px;width:100%"></div>
      </body>
    </html>

    【讨论】:

      【解决方案5】:

      您之所以只找到“addEventListener”示例是因为您需要处理这个跨浏览器:

      var supportedWheelEvent = "onwheel" in HTMLDivElement.prototype ? "wheel" : document.onmousewheel !== undefined ? "mousewheel" : "DOMMouseScroll";
      

      另外,最好只对一个元素执行此操作!使用委托事件侦听器来处理您需要的所有元素。

      HTML 示例:

      <div id="delegator">
         <div class="handleWheel">handle wheel event here</div>
         <div> no wheel event handled here </div>
         <div class="handleWheel">handle wheel event here</div>
         <div> no wheel event handled here </div>
      </div>
      

      JS:

      var supportedWheelEvent = "onwheel" in HTMLDivElement.prototype ? "wheel" : document.onmousewheel !== undefined ? "mousewheel" : "DOMMouseScroll";
      
      function handler(e){
          if(e.target.classList.contains('handleWheel')){
              // handle the event here
          }
      }
      
      var d = document.getElementById('delegator');
      d.addEventListener(supportedWheelEvent, handler);
      

      工作代码笔示例: https://codepen.io/Mchaov/pen/zwaMmM

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2016-09-06
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2012-05-05
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多