处理动态生成的输入字段上的事件的最佳方法是什么?

huangapple go评论66阅读模式
英文:

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(&#39;inputs&#39;);
// 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(&#39;click&#39;, () =&gt; {
    const i = document.createElement(&#39;input&#39;);
    i.type = &quot;text&quot;;
    inputs.append(i);
});

const log = (e) =&gt; {
  const event = document.createElement(&#39;div&#39;);
  event.innerText = `${e.type}: on ${e.target.tagName}`;
  events.prepend(event);
};


const inputsHTMLCollection = document.getElementsByTagName(&#39;input&#39;);
for (let i of inputsHTMLCollection) {
  i.addEventListener(&#39;focus&#39;, log);
};

// After addinput click - the inputsHTMLCollection length will be changed
// some code, for detect length change here

<!-- language: lang-css -->

body {
  display: flex;
}

body &gt; div {
  flex: 0 0 50%;
}

input {
  display: block;
}

<!-- language: lang-html -->

&lt;div id=&quot;inputs&quot;&gt;
  &lt;button id=&#39;addinput&#39;&gt;Add input field&lt;/button&gt;
  &lt;input type=&quot;text&quot; /&gt;
&lt;/div&gt;
&lt;div id=&quot;events&quot;&gt;&lt;/div&gt;

<!-- 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事件focusfocusin之间的一个区别是,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(&#39;focus&#39;, function(event){ ... }, true);
/* OR */
document.addEventListener(&#39;focus&#39;, 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(&#39;focusin&#39;, 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(&#39;focus&#39;, (e) =&gt; console.log(&#39;focus&#39;, &#39;useCapture&#39;), true);
document.addEventListener(&#39;focus&#39;, (e) =&gt; console.log(&#39;focus&#39;, &#39;{ capture: true }&#39;), { capture: true });
document.addEventListener(&#39;focusin&#39;, (e) =&gt; console.log(&#39;focusin&#39;));

<!-- language: lang-html -->

&lt;input&gt;

<!-- 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(&#39;button&#39;).addEventListener(&#39;click&#39;, e =&gt; {

  e.target.remove();

  document.querySelector(&#39;.container&#39;).innerHTML = `
    &lt;input id=&quot;Text&quot;&gt;
    &lt;button class=&quot;btn&quot;&gt;Auto click me&lt;/button&gt;
    &lt;div class=&quot;log&quot;&gt;&lt;/div&gt;
  `;

  const textbox = document.querySelector(&#39;#Text&#39;);
  textbox.focus();

  document.querySelector(&#39;.btn&#39;).addEventListener(&#39;click&#39;, () =&gt; {
    document.querySelector(&#39;.log&#39;).innerHTML += `&lt;div&gt;${textbox.value.trim()}&lt;/div&gt;`;
    textbox.value = &#39;&#39;;
  });
  
});

// your code, watch for inputs to change

document.addEventListener(&#39;input&#39;, e =&gt; {

  const button = document.querySelector(&#39;.btn&#39;);

  e.target.value.trim().length === 5 &amp;&amp; setTimeout(() =&gt; button.click(), 100);

});

<!-- language: lang-html -->

&lt;button&gt;Add elements&lt;/button&gt;
&lt;div class=&quot;container&quot;&gt;&lt;/div&gt;

<!-- end snippet -->

huangapple
  • 本文由 发表于 2023年6月1日 16:04:28
  • 转载请务必保留本文链接:https://go.coder-hub.com/76379853.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定