能否将点击事件附加到文档片段中?

7

我尝试过的方法:

// creating elements
var container = document.createDocumentFragment();
var headline = document.createElement('h1');
headline.innerHTML = 'This is a headline.';

// attaching to DOM
container.appendChild(headline);
document.body.appendChild(container);

// attaching click event
container.addEventListener('click', function () {
    console.log(arguments);
});

这个例子无法正常工作。事件没有被触发。

是否有任何方法可以将点击事件附加到文档片段中,还是根本不可能?

3个回答

8
在这种情况下,单击事件将无法工作,因为文档片段没有附加到DOM结构中。以下是有关此的文档所说的内容:

各种其他方法可以将文档片段作为参数(例如任何Node接口方法,如Node.appendChildNode.insertBefore),在这种情况下,将附加或插入片段的子项,而不是片段本身。

因此,“片段的子项被附加,而不是片段本身”。这意味着绑定到片段的单击事件几乎没有用处,因为它位于DOM之外,无法被单击访问。

2
你的意思是“它不起作用”是什么意思?只是无法点击,但如果可能的话,例如 container.dispatchEvent(new Event("click")); 它应该还是会起作用的。 - hanshenrik
1
当然,但我认为我们正在谈论appendChild的行为。无论如何,如果您觉得添加dispatchEvent很重要,那么请发布答案,我认为这将是有用的。 - dfsq

3

有两个问题阻止你的代码工作

事件和DocumentFragment

首先,正如@dfsq所说,container的值是一个DocumentFragment。当你稍后调用appendChild时,DocumentFragment的内容会被移动到DOM中,但片段本身不会被移动。这意味着事件监听器被"遗留",永远不会被点击触发。

解决方法是将事件监听器附加到container的一个子元素上,比如headline

headline.addEventListener('click', ...

通常情况下,你没有直接的参考,比如当你使用模板和.cloneNode。在许多情况下,片段只包含一个元素,因此使用container.firstElementChild是一个不错的选择。如果你的片段更复杂,你可能需要使用.querySelector或类似的方法。

container.appendChild(headline);
container.firstElementChild.addEventListener('click', // ...

DocumentFragment.appendChild

其次,当你调用 document.body.appendChild 时,文档片段的内容会被“移动”到 DOM 中,并且离开了文档片段。文档片段不再保留引用。这意味着一个节点不能有两个父节点。这意味着在调用 addEventListener 时,没有任何节点可以触发事件!

解决方法是在调用 .appendChild 之前附加事件监听器。

解决方案

将这两个步骤结合起来,得到以下实现:

// creating elements
var container = document.createDocumentFragment();
var headline = document.createElement('h1');
headline.innerHTML = 'This is a headline.';

// attaching click event
headline.addEventListener('click', function () {
    console.log('click happened!');
});

// attaching to DOM
container.appendChild(headline);
document.body.appendChild(container);


1

这里有一个示例,展示如何创建一个片段来获取HTML组件并在其上附加事件...

function createFragmentWithEvent(){
    let html = ` 
    <div style="display: flex; flex-direction: column;">
        <div style="display: flex; align-items: center; padding: 5px;">   
            <img style="width: 40px; height: 40px; " src="${value.profilPicture_}"></img>
            <div style="display: flex; flex-direction: column; font-size: .85em; padding-left: 8px;">
                <span>${value._id}</span>
                <span>${value.email_}</span>
            </div>
        </div>
        <paper-button style="font-size:.65em; width: 20px; align-self: flex-end;" id="${value._id}_invite_btn">Invite</paper-button>
    </div>`
    let range = document.createRange()
    let fragment = range.createContextualFragment(html)
    let inviteBtn = fragment.getElementById(value._id + "_invite_btn")
    inviteBtn.onclick = ()=>{
        console.log("----> invite ", value)
    }
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接