【问题标题】:Firefox's onInput with contentEditable inside a <span> isn't workingFirefox 在 <span> 内带有 contentEditable 的 onInput 不起作用
【发布时间】:2019-11-06 15:28:05
【问题描述】:

我一直在玩弄 onInput 和 contentEditable,试图制作一个可以自动显示一些数学总和的脚本。部分概念是让输入随着用户键入而增长,我发现使用 contentEditable 的&lt;span&gt; 标签可以很好地工作。我所做的大部分测试都是在 Google Chrome 上进行的,它似乎在那里工作,但 onInput 似乎在 Firefox (4.0) 中不起作用。然而,onKeyUp 在 Firefox 中有效,但不像 onInput 那样即时。

<div id="f">
    <span oninput="go()" id="p" class="x" contenteditable="true">0
    </span>
    % of
    <span oninput="go()" id="n" class="x" contenteditable="true">0
    </span>
    =
    <span id="r" class="x" contenteditable="true">0
    </span>
    <p id="a"></p>
</div>

function go() {
    p = document.getElementById('p').innerHTML;
    n = document.getElementById('n').innerHTML;
    r = document.getElementById('r');
    a = document.getElementById('a');
    r.innerHTML = p / 100 * n;
    a.innerHTML = p + "% of " + n + " equals " + p / 100 * n;
}

看看the script over at jsFiddle

谢谢。

【问题讨论】:

    标签: javascript firefox html contenteditable


    【解决方案1】:

    Firefox 中的 contenteditable 不支持 input 事件。很可能会在未来发生,但就目前而言,您将不得不使用更笨重的拦截各种其他事件的方法。您的选项是keypresskeyupmouseuppastecutcopy 的组合,或者更简单的是,如果您可以忽略 IE DOM mutation events。拦截DOMNodeInsertedDOMNodeRemovedDOMCharacterDataModified 应该可以解决问题:

    document.addEventListener("DOMNodeInserted", go, false);
    document.addEventListener("DOMNodeRemoved", go, false);
    document.addEventListener("DOMCharacterDataModified", go, false);
    

    您需要注意的一件事是,在 WebKit 中,DOM 突变事件对于可编辑内容是异步的。

    【讨论】:

      【解决方案2】:

      我意识到这不再是已知 html 元素的问题,但是,对于没有 oninput 方法的元素(例如自定义元素)来说,这仍然是一个非常现实的问题(例如 @987654322 @)。是的,我知道有一种正确的方法可以创建此类用户定义的元素,但这不是,但无论如何,以下方法有效,并且可能对真正旧浏览器中的已知 HTML 元素有益。

      我写了一段代码,可以与 any 元素一起使用。它利用事件委托并跟踪为元素注册的事件。只需在您的页面中包含以下 JavaScript。

      /*-----------------------------------------------------------------------------------*/
      /*------------------- code to add document-level event delegation -------------------*/
      /*-----------------------------------------------------------------------------------*/
      // create an array for storing events
      var documentLevelEvents = [];
      
      // add a new delegated document-level listener function to all objects of type Element
      Element.prototype.addDocumentLevelEventListener = function (eventType, fn) {
          // get a count of registered document-level event listeners for a given event type
          function documentLevelEventListenerCount(eventType) {
              var eventCount = documentLevelEvents.filter(e => {
                  return e.eventType === eventType;
              }).length;
              return eventCount;
          }
      
          // filter the documentLevelEvents array and return only those that match the 
          // specified element and eventType
          function getDocumentLevelEvents(element, eventType) {
              var events = documentLevelEvents.filter(function (e) {
                  return e.element === element && e.eventType === eventType;
              });
              return events;
          }
      
          // grab the count of listeners registered for this event type before registering
          // the submitted event
          var listenerExists = documentLevelEventListenerCount(eventType);
      
          // register the new document-level event listener
          documentLevelEvents.push({
              eventType: eventType,
              element: this,
              fn: fn
          });
      
          // if the document object does not already have a listener for this event type,
          // create a new event listener on the document object.
          if (!listenerExists) {
              document.addEventListener(eventType, function (evt) {
                  var target = evt.target;
      
                  // get an array of all registered events matching the target element
                  // and the triggered event type
                  var events = getDocumentLevelEvents(target, eventType);
                  // iterate through the array and run the registered listener functions
                  for (var i = 0; i < events.length; ++i) {
                      event = events[i];
                      event.fn(evt);
                  }
              });
          }
      };
      
      /*-----------------------------------------------------------------------------------*/
      /*---------------------------------- example usage ----------------------------------*/
      /*-----------------------------------------------------------------------------------*/
      element = document.getElementById('#element-id');
      element.addDocumentLevelEventListener('input', ()=>{console.log('innerText changed!')})
      // anytime the text of the element changes on account of input, a notice will be logged
      // to console.
      

      这里发生了什么? 我们为所有 Element 类型的对象(或扩展 Element 的对象)添加了一个新函数。此函数创建一个委托事件侦听器,该侦听器使用 document 对象来侦听事件。为了确保我们的事件仅限于指定的元素,我们在 documentLevelEvents 数组中跟踪所有已注册的事件。当我们注册的文档侦听器之一听到事件时,它会检查事件数组以查看它是否匹配一个或多个已注册的元素/事件绑定。对于它找到的每个匹配项,它都会运行传递给 addDocumentLevelListener 函数的函数,并传递事件。

      这是一个jsfiddle,它显示了它的实际效果。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2016-10-24
        • 2012-03-24
        • 1970-01-01
        • 2015-06-10
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多