最近在写js的时候遇见一个奇怪的问题
$(select).html(某些元素);
$(某些元素).on(一些事件);
上面这两行代码很简单,第一行就是给原定元素增加一些新元素,第二行是对这些新增加的元素绑定一些事件。但是在多次运行的时候会偶尔出现问题,总会发生几次html(某些元素)还没有写完“某些元素”,第二行的on(一些事件)就执行了。此时因为html()还没完成,所以那些元素还不在页面上,所以第二句$(某些元素)找不到对象报错。
简单说就是第一行的html()还没完成,第二行的on()就执行了。实际上不管第二行是on()也好css()也好,都会发生这种提前执行的情况。
在网上问了一圈,有人提到用on()的事件代理可以解决
$(select).on( events [, selector ] [, data ], handler )
selector
Type: String
A selector string to filter the descendants of the selected elements that trigger the event. If the selector is null or omitted, the event is always triggered when it reaches the selected element.
https://api.jquery.com/on/
已有父节点A,要在父元素里创建子节点B并给B绑定事件。可以把事件绑定到A上,就是楼上说的事件代理。
假设A的class名为parent,B的class名为child,就可以这样写:
$(‘.parent’).on(‘click’, ‘.child’, 事件).append(‘<div class=”child”></div>’);
但是有一个进阶问题,当第二行是css()的时候无事件可以绑定,即无法使用on的时候怎么办。对此网上也有如下解释
这个问题虽然很常见, 但是产生原因很底层. 就是浏览器的DOM元素更新和JS的执行并不一致, 如果想要等待DOM真正更新完成再执行下一步操作, 那么就必须监听DOM元素在浏览器的更新是否完成, 再执行下一步操作
是真正想解决这个问题可能要用到MutationObserver或者MessageChannel等API, 其中还涉及到浏览器兼容性问题, 楼主有兴趣可以钻研一下.
没兴趣的话, 用Vue等前端框架重构一下, 框架提供了大量方便的方法来实现类似功能.
到目前我能想到一个办法,虽然有点蠢,但确实有效。利用setInterval设置一个定时器,在html()后不断检测新增加的元素,一直到检测到该元素再执行后面的内容。
$(select).html(new ele + "<div id='EndFlag'></div>")
//我不确定上面这种写法是否能行,总之就是在新增的元素中增加或者选取一个标识符
let t = setInterval(function () {
let end = $("#EndFlag");
if (end.length > 0){
clearInterval(t);
do whatever you want
}
}, 1000)













