8wDlpd.png
8wDFp9.png
8wDEOx.png
8wDMfH.png
8wDKte.png

ES6 模块:导入后未定义 onclick 函数

GohanHango 2月前

71 0

我正在测试 ES6 模块,并希望让用户使用 onclick:test.html 访问一些导入的函数: <...

我正在测试 ES6 模块,并希望让用户使用以下方式访问一些导入的功能 onclick

测试.html:

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <title>Module Test</title>
</head>
<body>
    <input type="button" value="click me" onclick="hello();"/>
    <script type="module">import {hello} from "./test.js";</script>
</body>
</html>

测试.js:

export function hello() {console.log("hello");}

当我单击按钮时,开发人员控制台显示: ReferenceError: hello is not defined 。如何从模块导入函数,以便它们可用作 onclick 函数?

我使用的是 Firefox 54.0, dom.moduleScripts.enabled 设置为 true .

帖子版权声明 1、本帖标题:ES6 模块:导入后未定义 onclick 函数
    本站网址:http://xjnalaquan.com/
2、本网站的资源部分来源于网络,如有侵权,请联系站长进行删除处理。
3、会员发帖仅代表会员个人观点,并不代表本站赞同其观点和对其真实性负责。
4、本站一律禁止以任何方式发布或转载任何违法的相关信息,访客发现请向站长举报
5、站长邮箱:yeweds@126.com 除非注明,本帖由GohanHango在本站《function》版块原创发布, 转载请注明出处!
最新回复 (0)
  • thd 2月前 0 只看Ta
    引用 2

    此功能被标记为实验性的,我现在不会使用它。你最好转换(Babel?)你的代码以确保它可以在任何浏览器中运行,不是吗?

  • 模块创建一个范围以避免名称冲突。

    您可以使用 addEventListener 来绑定处理程序。 演示

    <button type="button" id="hello">Click Me</button>
    <script type="module">
      import {hello} from './test.js'
      
      document.querySelector('#hello').addEventListener('click', hello)
    </script>
    

    或者你可以把你的功能暴露给对象 window ,但是我们不推荐这样做。

    import {hello} from './test.js'
      
    window.hello = hello
    
  • 想要编辑此答案并完全删除窗口方法或至少添加警告。除了上述原因之外,这仍会在那里留下一个 onclick 属性。这些都是不好的做法,是一种过时、繁琐且不直观的事件监听方式。上一个需要这些的浏览器在近二十年前就已达到 EOL,因此这种方法与现代编程无关。始终使用 addEventListener。

  • 是的,选项 2 的缺点是它损害了可读性。现在,您不必检查 HTML 中的按钮并使用面包屑将其链接到 JS,而是必须在代码中查找 addEventListener 和/或元素 ID,直到找到正确的按钮。基本上,当处理程序绑定纯粹用 JS 实现时,您如何回答“当我单击此按钮时会发生什么”这个问题?似乎没有直接的方法可以回答这个问题,您必须四处查找。

  • @Gillespie 浏览器开发者工具中的 Inspector 应该能够处理这种情况。结构良好、模块化的代码在用户交互方面应该易于扫描。

  • @TheEmptyStringPhotographer 你可以想出一个命名约定来使碰撞不太可能发生,但这并不意味着你应该这样做。:) 大多数时候,您希望在自己的边界内隔离特征(又名“模块”)。

  • 中的模块范围 ES6

    当您使用以下方式导入脚本时 type="module"

    <script type="module">import {hello} from "./test.js";</script>
    

    您正在创建一个名为模块范围的特定范围。这里是模块范围相对于其他级别范围的位置。从全局开始,它们是:

    1. 全局范围:最外层模块之外的所有声明(即不在函数中,以及 for const let 不在块中)都可以从 Javascript 运行时环境中的任何地方访问
    2. 模块作用域:模块内的所有声明都作用于该模块。当其他 javascipt 尝试访问这些声明时,它将引发引用错误。
    3. 函数作用域:函数体内(顶层)声明的所有变量都属于函数作用域
    4. 块作用域: let 也是 const 块作用域

    您之所以会得到 referenceError 错误,是因为该 hello() 函数是在模块中声明的,而该模块是 模块作用域 。正如我们之前看到的,模块作用域内的声明仅在该模块内可用,而您试图在模块外使用它。

    明确地 模块内部的声明 放在 窗口 对象上时,我们可以将其声明为全局声明,以便我们可以在模块外部使用它。例如:

    window.hello = hello;  // putting the hello function as a property on the window object
    
  • 哦,那么这是否意味着脚本标签中没有模块类型的函数被放在全局范围内,并且可以在外部脚本中使用?

  • 虽然接受的答案是正确的,但是一旦您开始从多个模块导入或声明多个函数,它的扩展性就会很差。 此外,正如@Quentin所指出的,它有造成全局名称空间污染的风险。

    我更喜欢稍微修改一下

    import { doThis, doThat } from './doStuff.js'
    import { foo1, foo2 } from './foo.js'
    
    function yetAnotherFunction() { ... }
    
    window._allTheFns = { doThis, doThat, foo1, foo2, yetAnotherFunction }
    
    // or, if you prefer, can subdivide
    
    window._doStuffjs = { doThis, doThat }
    window._foojs = { foo1, foo2 }
    
    1. 使用“不寻常”的属性名称(希望)避免全局命名空间问题
    2. 无需立即附加(或 忘记 附加)EventListener。
    3. 你甚至可以将监听器放在 HTML 中,例如 <button onclick="window._foojs.foo1(this)">Click Me</button>
  • 令人震惊 :) 很难相信 ES 不允许命名空间限定来简化这一点。有一件事。在 window._allTheFns = { doThis, doThat, foo1, foo2, yetAnotherFunction } 中进行分配之前,值得检查命名空间是否存在

  • 截至 2022 年,除了提供的解决方案之外,我不知道还有其他解决方案,除非您不需要使用窗口,但可以使用 globalThis

    我不知道这是否会使情况变得更好。

    优点:

    • 这是一个更易读的
    • 当 checkJS 处于打开状态时,您不会收到编译器错误(在窗口等上未找到属性 \'...\'...)

    我甚至使用带有 @event 符号的 LitHtml,如下所示:

    <element @click="${(e)=>console.log(e)}"></element>
    

    但遗憾的是,没有干净的方法来实际获取附加了侦听器的对象的引用。target、originalTarget 和 explicitOrOriginalTarget 可以是冒泡队列中的任何内容,这非常烦人且非常令人困惑,但如果您不需要这样,LitHTML 就是您的最佳选择。

返回
作者最近主题: