ES6 模块:导入后未定义的 onclick 函数
ES6 Modules: Undefined onclick function after import
我正在测试 ES6 模块并想让用户使用 onclick
:
访问一些导入的函数
test.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>
test.js:
export function hello() {console.log("hello");}
当我点击按钮时,开发者控制台显示:ReferenceError: hello is not defined。我如何从模块中导入函数,以便它们可以作为 onclick 函数使用?
我正在使用 Firefox 54.0,dom.moduleScripts.enabled
设置为 true
。
模块创建一个范围以避免名称冲突。
将您的函数公开给 window
对象
import {hello} from './test.js'
window.hello = hello
或使用addEventListener
绑定处理程序。 Demo
<button type="button" id="hello">Click Me</button>
<script type="module">
import {hello} from './test.js'
document.querySelector('#hello').addEventListener('click', hello)
</script>
ES6
个模块中的模块范围:
当您使用type="module"
以下列方式导入脚本时:
<script type="module">import {hello} from "./test.js";</script>
您正在创建一个称为模块范围的特定范围。这是模块范围相对于其他级别范围的位置。从全局开始,它们是:
- 全局范围:在最外层的模块外的所有声明(即不在函数中,
const
和 let
不在块中)可以从 Javascript运行时环境
- 模块范围:模块内的所有声明都限定在模块范围内。当其他 javascipt 尝试访问这些声明时,它将抛出引用错误。
- 函数作用域:在函数体内部(顶层)声明的所有变量都是函数作用域
- 块作用域:
let
和 const
变量是块作用域的
您收到 referenceError 是因为 hello()
函数是在模块中声明的,该模块是 模块作用域 。正如我们之前看到的,模块范围内的声明仅在该模块内可用,而您试图在模块外使用它。
当我们显式将它放在window对象上时,我们可以在全局模块内进行声明,这样我们就可以使用它在模块之外。例如:
window.hello = hello; // putting the hello function as a property on the window object
虽然接受的答案是正确的,但一旦您开始从多个模块导入或声明多个函数,它的扩展性就会很差。另外,正如@Quentin 所指出的,它有全球名称 space 污染的风险。
我更喜欢稍微修改一下
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 }
- 使用“不寻常的”属性 名称来(希望)避免全局名称space 问题
- 无需立即附加(或忘记附加)EventListener。
- 您甚至可以将侦听器放在 HTML 中,例如
<button onclick="window._foojs.foo1(this)">Click Me</button>
我正在测试 ES6 模块并想让用户使用 onclick
:
test.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>
test.js:
export function hello() {console.log("hello");}
当我点击按钮时,开发者控制台显示:ReferenceError: hello is not defined。我如何从模块中导入函数,以便它们可以作为 onclick 函数使用?
我正在使用 Firefox 54.0,dom.moduleScripts.enabled
设置为 true
。
模块创建一个范围以避免名称冲突。
将您的函数公开给 window
对象
import {hello} from './test.js'
window.hello = hello
或使用addEventListener
绑定处理程序。 Demo
<button type="button" id="hello">Click Me</button>
<script type="module">
import {hello} from './test.js'
document.querySelector('#hello').addEventListener('click', hello)
</script>
ES6
个模块中的模块范围:
当您使用type="module"
以下列方式导入脚本时:
<script type="module">import {hello} from "./test.js";</script>
您正在创建一个称为模块范围的特定范围。这是模块范围相对于其他级别范围的位置。从全局开始,它们是:
- 全局范围:在最外层的模块外的所有声明(即不在函数中,
const
和let
不在块中)可以从 Javascript运行时环境 - 模块范围:模块内的所有声明都限定在模块范围内。当其他 javascipt 尝试访问这些声明时,它将抛出引用错误。
- 函数作用域:在函数体内部(顶层)声明的所有变量都是函数作用域
- 块作用域:
let
和const
变量是块作用域的
您收到 referenceError 是因为 hello()
函数是在模块中声明的,该模块是 模块作用域 。正如我们之前看到的,模块范围内的声明仅在该模块内可用,而您试图在模块外使用它。
当我们显式将它放在window对象上时,我们可以在全局模块内进行声明,这样我们就可以使用它在模块之外。例如:
window.hello = hello; // putting the hello function as a property on the window object
虽然接受的答案是正确的,但一旦您开始从多个模块导入或声明多个函数,它的扩展性就会很差。另外,正如@Quentin 所指出的,它有全球名称 space 污染的风险。
我更喜欢稍微修改一下
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 }
- 使用“不寻常的”属性 名称来(希望)避免全局名称space 问题
- 无需立即附加(或忘记附加)EventListener。
- 您甚至可以将侦听器放在 HTML 中,例如
<button onclick="window._foojs.foo1(this)">Click Me</button>