我想覆盖JavaScript中所有HTML元素的函数focus()
。
我怎么做?
最佳答案
该问题仅要求如何为HTML元素覆盖.focus()
方法,因此将首先对其进行回答。但是,还有其他触发“关注”元素的方法,下面讨论了覆盖这些方法的方法。
另请注意,覆盖全局原型(prototype)可能不是一个好主意。
在HTML元素上覆盖.focus()
方法
您可以通过修改其原型(prototype)来覆盖所有HTMLElement
的focus函数。
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
原型(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);
};
如果您根本不想要原始行为,则可以删除
func
调用(func(e)
)。覆盖通过
onfocus
属性设置的焦点事件这样做实际上是很棘手的,并且很可能会有一些无法预见的局限性。就是说,我找不到通过修改原型(prototype)等方法覆盖此方法的唯一方法。我可以通过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()">