5

我想覆盖focus()JavaScript 中所有 HTML 元素的函数。

我怎么做?

4

2 回答 2

9

该问题询问如何覆盖 HTML 元素的.focus() 方法,因此将首先回答。但是,还有其他方法可以触发对元素的“关注”,下面将讨论覆盖这些方法。

另请注意,覆盖全局原型可能不是一个好主意


覆盖.focus()HTML 元素上的方法

HTMLElement您可以通过修改其原型来覆盖 all 的焦点功能。

HTMLElement.prototype.focus = function () {
  // ... do your custom stuff here
}

如果您仍想运行默认焦点行为并运行自定义覆盖,您可以执行以下操作:

let oldHTMLFocus = HTMLElement.prototype.focus;
HTMLElement.prototype.focus = function () {
    // your custom code
    oldHTMLFocus.apply(this, arguments);
};

通过 HTML 元素上的处理程序覆盖焦点事件集

这以与覆盖该方法类似的方式完成.focus()。但是,在这种情况下,我们将针对EventTarget构造函数并修改addEventListener原型:

let oldAddListener = HTMLElement.prototype.addEventListener;
EventTarget.prototype.addEventListener = function () {
    let scope = this;
    let func = arguments[1];

    if (arguments[0] === 'focus') {
        arguments[1] = function (e) {
            yourCustomFunction(scope);
            func(e);
        };
    }

    oldAddListener.apply(this, arguments);
};

如果您根本不想要原始行为,则可以删除func调用 ( func(e))。


覆盖通过onfocus属性设置的焦点事件

这样做实际上非常棘手,并且很可能会有一些无法预料的限制。也就是说,我找不到通过修改原型等来覆盖它的方法。我可以完成这项工作的唯一方法是使用MutationObservers。它通过查找所有具有该属性的元素来工作,onfocus并将第一个函数设置为运行覆盖函数:

let observer = new MutationObserver(handleOnFocusElements);
let observerConfig = {
    attributes: true,
    childList: true,
    subtree: true,
    attributeFilter: ['onfocus']
};
let targetNode = document.body;

observer.observe(targetNode, observerConfig);

function handleOnFocusElements() {
    Array
        .from(document.querySelectorAll('[onfocus]:not([onfocus*="yourCustomFunction"])'))
        .forEach(element => {
            let currentCallbacks = element.getAttribute('onfocus');
            element.setAttribute('onfocus', `yourCustomFunction(this); return; ${currentCallbacks}`);
        });
}

如果您想完全阻止原始 onfocus 触发其事件,您可以在任何突变更改时完全清空 onfocus 属性,并将值设置为您想要的函数。


一个包含所有代码片段的示例:

(function() {

  window.yourCustomFunction = function(target) {
    console.log('OVERRIDE on element', target);
  };

  let observer = new MutationObserver(handleOnFocusElements);

  let observerConfig = {
    attributes: true,
    childList: true,
    subtree: true,
    attributeFilter: ['onfocus']
  };

  let targetNode = document.body;

  // Start overriding methods
  // The HTML `.focus()` method
  let oldHTMLFocus = HTMLElement.prototype.focus;
  HTMLElement.prototype.focus = function() {
    yourCustomFunction(this);
    oldHTMLFocus.apply(this, arguments);
  };

  // Event Target's .addEventListener prototype
  let oldAddListener = HTMLElement.prototype.addEventListener;
  EventTarget.prototype.addEventListener = function() {
    let scope = this;
    let func = arguments[1];

    if (arguments[0] === 'focus') {
      arguments[1] = function(e) {
        yourCustomFunction(scope);
        func(e);
      };
    }

    oldAddListener.apply(this, arguments);
  };

  // Handle the onfocus attributes
  function handleOnFocusElements() {
    Array
      .from(document.querySelectorAll('[onfocus]:not([onfocus*="yourCustomFunction"])'))
      .forEach(element => {
        let currentCallbacks = element.getAttribute('onfocus');
        element.setAttribute('onfocus', `yourCustomFunction(this); return; ${currentCallbacks}`);
      });
  }

  window.addEventListener('load', () => {
    handleOnFocusElements();
    observer.observe(targetNode, observerConfig);
  });
})();

let input = document.querySelector('input');

input.addEventListener('focus', function() {
  console.log('Add Event Listener Focus');
});

function attributeHandler() {
  console.log('Called From the Attribute Handler');
}
<input type="text" onfocus="attributeHandler()">

于 2016-07-22T19:32:26.117 回答
-1

在纯 JS 中:

HTML:

<input id="test" type="textfield" />​

JS:

var myInput = document.getElementById("test");
myInput.addEventListener("focus",deFocus(myInput),true);

function deFocus(element) {
    element.setAttribute('readonly','readonly');
    return false;
}

工作小提琴

在 JQuery 中:

HTML

​&lt;input id="test" type="textfield" />

jQuery

​$('#test').focus(function() {
    $(this).blur();
});​​​​​​​​​​​​​​​​​​​​

工作小提琴

您可以将其添加EventListener到您想要的任何内容、类、id 等,并通过函数运行它或触发其他东西来解锁它们。JQuery 也可以非常顺利地处理这个问题,但如果你走那条路,我建议使用一个类作为选择器,然后你可以动态添加和删除该类以禁用焦点。

于 2012-11-03T20:21:26.170 回答