处理尚不存在的 DOM 节点

科技资讯 投稿 5700 0 评论

处理尚不存在的 DOM 节点

有时候,您需要操作尚未存在的 DOM 的某个部分。

blur事件的响应并没有得到工具的正式支持,所以我打算自己来设计一个事件监听器。然而,通过像.querySelector(这样的方法来尝试访问节点会返回null,因为此时节点还没有被浏览器渲染,并且我也不知道究竟什么时候会被渲染。

// Simulating lazily-rendered HTML:
setTimeout(( => {
	const button = document.createElement('button';
	button.id = 'button';
	button.innerText = 'Do Something!';

 	document.body.append(button;
}, randomBetweenMs(1000, 5000;

document.querySelector('#button'.addEventListener('click', ( => {
	alert('clicked!'
};

// Error: Cannot read properties of null (reading 'addEventListener'

真的是毫无意外。你看到的所有代码都会被丢进调用栈并立即执行(当然,除了setTimeout的回调函数),所以当我试图访问按钮时,我所得到的便是null

轮询

setInterval或者setTimeout这样的方法,下面是使用递归的例子:

function attachListenerToButton( {
  let button = document.getElementById('button';

  if (button {
    button.addEventListener('click', ( => alert('clicked!';
    return;
  }

	// If the node doesn't exist yet, try
	// again on the next turn of the event loop.
  setTimeout(attachListenerToButton;
}

attachListenerToButton(;

或者,你可能已经见过一种基于Promise的方法,这感觉更现代一些:

async function attachListenerToButton( {
  let button = document.getElementById('button';

  while (!button {
		// If the node doesn't exist yet, try
		// again on the next turn of the event loop.
    button = document.getElementById('button';
    await new Promise((resolve => setTimeout(resolve;
  }

  button.addEventListener('click', ( => alert('clicked!';
}

attachListenerToButton(;

不管怎么说,这种策略都有非同小可的代价--主要是性能。在这两个版本中,移除setTimeout(会导致脚本完全同步运行,阻塞主线程,以及其他需要在主线程上进行的任务。没有输入事件会被处理。你的标签会被冻结。混乱不会随之而来。

setTimeout((或者setInterval),将下一次尝试推迟到到事件循环的下一个迭代中,这样就可以在这期间执行其他任务。但你仍然在重复地占用调用栈,等待你的节点出现。如果你想让你的代码很好地管理事件循环,那这就太不理想了。

click事件监听器,你不希望用户在几毫秒后才附加监听器之前就有机会点击该元素。这样的问题可能很少见,但当你稍后调试可能出错的代码时,它们肯定会带来烦恼。

MutationObserver(

body 内部任何变化的基本设置如下所示:

const domObserver = new MutationObserver((mutationList => {
	// document.body has changed! Do something.
};

domObserver.observe(document.body, { childList: true, subtree: true };

对于我们构造的示例,进一步完善也相当简单。每当树发生变化时,我们将查询特定的节点。如果节点存在,则附加监听器。

const domObserver = new MutationObserver(( => {
  const button = document.getElementById('button';

  if (button {
    button.addEventListener('click', ( => alert('clicked!';
  }
};

domObserver.observe(document.body, { childList: true, subtree: true };

我们传递给 .observe( 的选项很重要。将 childList 设置为 true 使观

编程笔记 » 处理尚不存在的 DOM 节点

赞同 (28) or 分享 (0)
游客 发表我的评论   换个身份
取消评论

表情
(0)个小伙伴在吐槽