英文:
What is the best way to handle events on dynamically generated input fields
问题
我正在寻找处理动态生成的输入字段上不同事件的最简单方法。
使用MutationObserver看起来很复杂,因为它需要处理列表中的每个MutationRecord,额外搜索输入字段并添加或移除监听器。
是否有替代MutationObserver的方法,比如使用HTMLCollection的某些技巧:
const inputsHTMLCollection = document.getElementsByTagName('input');
// 一些方法来检测inputsHTMLCollection的变化
更新
我正在寻找纯JS的替代解决方案,不使用任何库。
// 模拟页面上的代码
addinput.addEventListener('click', () => {
const i = document.createElement('input');
i.type = "text";
inputs.append(i);
});
const log = (e) => {
const event = document.createElement('div');
event.innerText = `${e.type}: on ${e.target.tagName}`;
events.prepend(event);
};
const inputsHTMLCollection = document.getElementsByTagName('input');
for (let i of inputsHTMLCollection) {
i.addEventListener('focus', log);
};
// 在addinput点击后,inputsHTMLCollection的长度将发生变化
// 在这里检测长度变化的一些代码
CSS部分:
body {
display: flex;
}
body > div {
flex: 0 0 50%;
}
input {
display: block;
}
HTML部分:
<div id="inputs">
<button id='addinput'>Add input field</button>
<input type="text" />
</div>
<div id="events"></div>
如果事件冒泡没有问题(对于点击或输入事件),但如何最好地处理动态添加的输入字段上的焦点事件?
我无法访问添加字段到页面的代码。我唯一拥有的是在页面加载后添加JS代码的能力。
英文:
I'm looking for the simplest way to handle different events on dynamically generated input fields.
Using MutationObserver looks complicated because requires processing each MutationRecord from the list, additional search for input fields and adding or removing listener.
Is there an alternative to MutationObserver like some hack with HTMLCollection:
const inputsHTMLCollection = document.getElementsByTagName('inputs');
// some way for detecting inputsHTMLCollection changing
UPD
I am looking for alternative solutions in pure JS, without using any libraries.
<!-- begin snippet: js hide: false console: true babel: false -->
<!-- language: lang-js -->
// emulate code on the page
addinput.addEventListener('click', () => {
const i = document.createElement('input');
i.type = "text";
inputs.append(i);
});
const log = (e) => {
const event = document.createElement('div');
event.innerText = `${e.type}: on ${e.target.tagName}`;
events.prepend(event);
};
const inputsHTMLCollection = document.getElementsByTagName('input');
for (let i of inputsHTMLCollection) {
i.addEventListener('focus', log);
};
// After addinput click - the inputsHTMLCollection length will be changed
// some code, for detect length change here
<!-- language: lang-css -->
body {
display: flex;
}
body > div {
flex: 0 0 50%;
}
input {
display: block;
}
<!-- language: lang-html -->
<div id="inputs">
<button id='addinput'>Add input field</button>
<input type="text" />
</div>
<div id="events"></div>
<!-- end snippet -->
There is no problems if an event bubbles (for click or input events), but what is the best way to handle focus events in dynamically added inputs?
I don't have access to the code that adds the fields to the page. All I have is the ability to add JS code after the page is loaded.
答案1
得分: 1
你需要的是事件代理。这类似于这个和这个,但这些问题没有涉及到不冒泡的事件,比如focus
事件。
要在不冒泡的事件上实现事件代理,你需要在事件捕获阶段捕获它。可以使用.addEventListener
方法的第三个参数来实现:
document.addEventListener('focus', function(event){ ... }, true);
/* 或者 */
document.addEventListener('focus', function(event){ ... }, { capture: true });
特别针对focus
事件,你也可以使用focusin
事件。focus
和focusin
之间的一个区别是,focusin
会冒泡:
document.addEventListener('focusin', function(event){ ... });
有关focus
事件的事件代理,可以参考这篇MDN文章。
<!-- 开始代码片段: js 显示: false 控制台: true Babel: false -->
<!-- 语言: lang-js -->
document.addEventListener('focus', (e) => console.log('focus', 'useCapture'), true);
document.addEventListener('focus', (e) => console.log('focus', '{ capture: true }'), { capture: true });
document.addEventListener('focusin', (e) => console.log('focusin'));
<!-- 语言: lang-html -->
<input>
<!-- 结束代码片段 -->
英文:
What you need is event delegation.
This is similar to this and this but those questions do not touch on events that do not bubble, like the focus
event.
To implement event delegation on events that do not bubble, you will need to catch it during event capturing phase. This can be done by using the third argument of the .addEventListener
method:
document.addEventListener('focus', function(event){ ... }, true);
/* OR */
document.addEventListener('focus', function(event){ ... }, { capture: true });
For the focus
event specifically, you can also use the focusin
event. One of the differences between focus
and focusin
is that focusin
bubbles:
document.addEventListener('focusin', function(event){ ... });
Event delegation for focus
event is discussed in this MDN article.
<!-- begin snippet: js hide: false console: true babel: false -->
<!-- language: lang-js -->
document.addEventListener('focus', (e) => console.log('focus', 'useCapture'), true);
document.addEventListener('focus', (e) => console.log('focus', '{ capture: true }'), { capture: true });
document.addEventListener('focusin', (e) => console.log('focusin'));
<!-- language: lang-html -->
<input>
<!-- end snippet -->
答案2
得分: 0
如果事件冒泡,您可以在document
上捕获它:
<button>添加元素</button>
<div class="container"></div>
// 模拟页面上的代码
document.querySelector('button').addEventListener('click', e => {
e.target.remove();
document.querySelector('.container').innerHTML = `
<input id="Text">
<button class="btn">自动点击我</button>
<div class="log"></div>
`;
const textbox = document.querySelector('#Text');
textbox.focus();
document.querySelector('.btn').addEventListener('click', () => {
document.querySelector('.log').innerHTML += `<div>${textbox.value.trim()}</div>`;
textbox.value = '';
});
});
// 您的代码,监听输入变化
document.addEventListener('input', e => {
const button = document.querySelector('.btn');
e.target.value.trim().length === 5 && setTimeout(() => button.click(), 100);
});
请注意,我已将代码和HTML分别放在代码块中以供清晰阅读。
英文:
If an event bubbles you can catch it at the document
:
<!-- begin snippet: js hide: false console: true babel: false -->
<!-- language: lang-js -->
// emulate code on the page
document.querySelector('button').addEventListener('click', e => {
e.target.remove();
document.querySelector('.container').innerHTML = `
<input id="Text">
<button class="btn">Auto click me</button>
<div class="log"></div>
`;
const textbox = document.querySelector('#Text');
textbox.focus();
document.querySelector('.btn').addEventListener('click', () => {
document.querySelector('.log').innerHTML += `<div>${textbox.value.trim()}</div>`;
textbox.value = '';
});
});
// your code, watch for inputs to change
document.addEventListener('input', e => {
const button = document.querySelector('.btn');
e.target.value.trim().length === 5 && setTimeout(() => button.click(), 100);
});
<!-- language: lang-html -->
<button>Add elements</button>
<div class="container"></div>
<!-- end snippet -->
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论