如何在JavaScript中覆盖所有元素的focus()?

时间:2012-10-31 14:08:03

标签: javascript

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

我该怎么做?

2 个答案:

答案 0 :(得分:9)

问题是如何覆盖HTML元素的.focus() 方法,以便首先回答。但是,还有其他方法可以触发“关注”元素,并在下面讨论重写这些方法。

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

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

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

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()">

答案 1 :(得分:-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;
}

工作fiddle

在JQuery中:

HTML

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

JQuery的

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

工作fiddle

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