React组件按钮点击时addEventListener首次不触发问题求助
问题原因分析
首次点击按钮时,事件触发顺序是这样的:
- 点击按钮 → 执行
loadJS函数 → 开始异步加载脚本文件 - 脚本加载完成后,才会执行里面的代码,给window绑定click事件监听
但此时本次点击事件已经完成冒泡和处理流程,新绑定的监听器根本没机会捕获这次点击,所以只输出TEST_1。
第二次点击时,监听器已经提前绑定好了,所以能正常触发TEST_2和TEST_3。
解决方案
方案一:直接在脚本加载后执行逻辑(推荐)
既然点击按钮就是为了触发脚本里的逻辑,没必要通过全局click监听绕一圈,直接让脚本暴露方法,在React的点击回调里调用:
修改JS文件
把IIFE改成模块导出方法:
"use strict"; console.log("TEST_1"); export function handleButtonClick() { console.log("TEST_2"); console.log("TEST_3"); actionFunc(); } function actionFunc() { // 这里写你的业务逻辑 }
修改React组件
异步加载脚本后,直接调用导出的方法:
const Component = () => { const loadJS = async () => { // 等待脚本加载完成 const { handleButtonClick } = await import(/* webpackChunkName: "od-survey" */ "./ol_od_survey.js"); // 执行脚本里的逻辑 handleButtonClick(); }; return ( <> <button className="button" onClick={loadJS}> Click Me </button> </> ); }; export default Component;
方案二:保留全局监听,但补处理首次点击
如果必须保留window的click监听逻辑,可以在脚本加载完成后,手动处理本次点击事件:
修改React组件
把点击事件对象传递给加载函数:
const Component = () => { const loadJS = async (event) => { const module = await import(/* webpackChunkName: "od-survey" */ "./ol_od_survey.js"); // 传递当前点击事件给脚本初始化 module.init(event); }; return ( <> <button className="button" onClick={loadJS}> Click Me </button> </> ); }; export default Component;
修改JS文件
在初始化时绑定监听并处理首次点击:
"use strict"; console.log("TEST_1"); export function init(initialEvent) { // 绑定全局click监听 window.addEventListener("click", handleClick); // 处理首次点击的按钮事件 if (initialEvent.target.textContent === "Click Me") { console.log("TEST_2"); console.log("TEST_3"); actionFunc(); } } function handleClick(event) { console.log("TEST_2"); if (event.target.textContent === "Click Me") { console.log("TEST_3"); actionFunc(); } } function actionFunc() { // 业务逻辑 }
额外注意点
- 原JS脚本里用
var声明actionFunc存在变量提升风险,建议改成function或const声明,避免全局变量污染。 - 全局绑定window的click事件会监听整个页面的点击,容易触发不必要的逻辑,优先推荐方案一,把逻辑和按钮点击直接绑定。
内容的提问来源于stack exchange,提问作者A.K
相关产品推荐
相关产品推荐

