嵌入在HTML中的ES6模块中定义的函数对该脚本不可用。因此,如果您有如下语句:
<button onclick="doSomething();">Do something</button>
在HTML和doSomething()函数中,在HTML脚本中嵌入的ES6模块中,在运行脚本时会出现一个"doSomething()是未定义的“错误。
直接在html中使用ES6模块中定义的函数为当前问题提出了一个很好的解决方案,建议您通过修改HTML将函数“绑定”到按钮上:
<button id="dosomethingbutton">Do something</button>
并使用模块本身创建链接:
document.getElementById('dosomethingbutton').addEventListener('click', doSomething);
这很好,但是如果您的原始按钮更复杂一些,并且是参数化的呢?例如:
<button onclick="doSomething('withThisString');">Do Something with String</button>
“绑定”所能提供的最大限度似乎仅限于与事件相关的情况--我无法找到将其与数据相关联的方法。我完全被困在试图找到解决这个问题的办法,并将非常感谢的帮助。
我想补充一点,虽然这个问题看起来有点模糊,但我认为任何迁移到Firebase 9的人都会对它感兴趣。迁移要求您将javascript代码移动到ES6模块中(在该模块中,HTML不能直接使用名称空间),因此最简单的HTML可能会立即遇到这些问题。非常欢迎你提出建议。
发布于 2021-10-26 09:35:39
这很好,但是如果您的原始按钮更复杂一些,并且是参数化的呢?
这方面有几个解决办法:
data-*属性:
用绳子做某事
document.getElementById("the-button").addEventListener("click",函数(){ doSomething(this.getAttribute("data-string"));};
(下文将对此作更多介绍。)
或上面有很多变体,如果使用带有不同字符串的多个按钮的doSomething,您可以使用类和循环来执行#1,而不是使用id,但这是一般的想法。
关于data-*属性的事情:如果您愿意,您可以通过data-*属性和一个连接起来的单一函数,使这个过程完全由data-*驱动。例如,假设您有以下按钮:
<button data-click="doThisx@module1">Do This</button>
<button data-click="doThat@module2">Do That</button>
<button data-click="doTheOther@module3">Do The Other</button>您可以使用一个可重用的函数将其连接起来:
class EventSetupError extends Error {
constructor(element, msg) {
if (typeof element === "string") {
[element, msg] = [msg, element];
}
super(msg);
this.element = element;
}
}
export async function setupModuleEventHandlers(eventName) {
try {
const attrName = `data-${eventName}`;
const elements = [...document.querySelectorAll(`[${attrName}]`)];
await Promise.all(elements.map(async element => {
const attrValue = element.getAttribute(`data-${eventName}`);
const [fname, modname] = attrValue ? attrValue.split("@", 2) : [];
if (!fname || !modname) {
throw new EventSetupError(
element,
`Invalid '${attrName}' attribute "${attrValue}"`
);
}
// It's fine if we do import() more than once for the same module,
// the module loader will return the same module
const module = await import(`./${modname}.js`);
const fn = module[fname];
if (typeof fn !== "function") {
throw new EventSetupError(
element,
`Invalid '${attrName}': no '${fname}' on module '${modname}' or it isn't a function`
);
}
element.addEventListener(eventName, fn);
}));
} catch (error) {
console.error(error.message, error.element);
}
}使用它查找并挂起单击处理程序:
import { setupModuleEventHandlers } from "./data-attr-event-setup.js";
setupModuleEventHandlers("click")
.catch(error => {
console.error(error.message, error.element);
});这是一次性的管道,但在HTML中提供了相同的基于属性的体验(事件处理程序仍然可以从另一个data-*属性获取参数信息,或者您可以将其放入安装函数中)。(该示例依赖于import,但这是所有主要浏览器的最新版本都支持,并在不同程度上依赖于绑定器。
有几十种方法来旋转它,我并不是在推广它,只是举一个例子,如果你愿意的话,你可以很容易地做一些事情。
但实际上,这是像React,Vue,Ember,角,Lit等图书馆发挥作用的地方。
发布于 2021-10-30 18:00:09
虽然T.JCrowder已经回答了这个问题,但我想我可能会添加一些很难作为评论的要点。
当我深入到Firebase V9转换中时,我开始发现“模块名称空间”问题的一些后果相当深远。我在最初的问题中引用的示例很容易处理,但我发现我还需要计算出如何处理响应于数据库中的可变环境的“动态”HTML。在这种情况下,我的javascript最初应该创建一个包含HTML块的字符串,如:
realDiv = `
<div>
<button onclick = "function fn1 (param1a, param1b,...);">button1</button>
<button onclick = "function fn2 (param2a, param2b,...);">button2</button>
etc
</div>
`,然后将其抛到应用程序的HTML框架中定义的“真实”realdiv中。
document.getElementById("realdiv") = realDiv;
现在,由于上述原因,一旦javascript在模块中,这种安排就不再有效。
我学会采用的模式(再次感谢T.J·克劳德)大致如下:
realDiv = `
<div>
<button id = "button1" data-param1a="param1a" data-param1b="param1b";">button1</button>
<button id = "button2" data-param2a="param2a" data-param2b="param2b";">button2</button>
etc
</div>
`然后,我会像以前一样将生成的代码放入HTML框架中。
document.getElementById("realdiv") = readlDiv;
现在,您已经将代码嵌入到DOM中(假设我对您生成的按钮数量进行了计数),我将使用最后一点javascript为它们创建绑定,如下所示:
for (let i = 0; i>buttonCount; i++) {
document.getElementById('button' + i).onclick = function() { fn1 (this.getAttribute('data-param1a'), this.getAttribute('data-param1b') };
etc
}我发现当我需要让onclick启动许多不同的功能时,用这种模式创建onclick对于保持清晰性特别有帮助。
https://stackoverflow.com/questions/69720620
复制相似问题