WebAssembly 本身无法直接操作 DOM,因为 WebAssembly 目标是提供一种可移植的、高效的二进制格式,以用于Web应用程序中的客户端和服务器端的计算密集型任务,而不能直接与 DOM 交互。然而,你可以通过 JavaScript 与 WebAssembly 之间的互操作来间接操作 DOM。
以下是一个简单示例,说明如何在 WebAssembly 中间接操作 DOM:
编写 C 代码(main.c):
#include <emscripten.h>
EM_JS(void, js_update_dom, (const char *text), {
const element = document.getElementById('wasm-output');
element.innerHTML = UTF8ToString(text);
});
void update_dom(const char *text) {
js_update_dom(text);
}
int main() {
update_dom("Hello from WebAssembly!");
return 0;
}
这段 C 代码使用了 Emscripten 提供的 EM_JS 宏定义一个 JavaScript 函数,用于更新 DOM。js_update_dom 函数接收一个 const char * 类型的参数,然后通过 JavaScript 代码找到指定的 DOM 元素,并更新其内容。
使用 Emscripten 编译 C 代码:
emcc main.c -s EXPORTED_FUNCTIONS='["_update_dom"]' -s EXTRA_EXPORTED_RUNTIME_METHODS='["cwrap", "UTF8ToString"]' -o main.js
这条命令使用 Emscripten 编译 main.c 文件,并生成 main.js 和 main.wasm 文件。通过设置 EXPORTED_FUNCTIONS 和 EXTRA_EXPORTED_RUNTIME_METHODS 选项,确保了需要的函数和方法可以在 JavaScript 中使用。
创建一个 HTML 文件(index.html)来加载和运行 WebAssembly 代码:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>WebAssembly DOM Manipulation</title>
<script async src="main.js"></script>
</head>
<body>
<h1 id="wasm-output"></h1>
<script>
Module.onRuntimeInitialized = function() {
Module._main();
};
</script>
</body>
</html>
在这个 HTML 文件中,加载了 main.js,并在 Module.onRuntimeInitialized 回调中调用 WebAssembly 生成的 _main 函数。WebAssembly 代码将间接操作 DOM,将 <h1> 元素的内容设置为 "Hello from WebAssembly!"。
运行此示例时,浏览器将显示 "Hello from WebAssembly!",这表明 WebAssembly 代码已成功间接操作 DOM。
除了使用EM_JS来定义一个javascript函数,还可以通过emscripten_set_click_callback函数来注册一个回调函数,来响应HTML元素的点击事件,例如下面的例子:
#include <emscripten.h>
EMSCRIPTEN_KEEPALIVE
void handle_click() {
// Do something with the DOM
}
int main() {
emscripten_set_click_callback("myButton", NULL, 1, handle_click);
return 0;
}
在上面的例子中,handle_click函数是一个在Wasm模块中定义的函数,它通过EMSCRIPTEN_KEEPALIVE宏来确保在编译时不会被优化掉。然后,该函数使用emscripten_set_click_callback函数来将自己注册为名为“myButton”的HTML元素的单击事件的回调函数。
在JavaScript中,可以通过以下方式来加载并调用Wasm模块中导出的函数:
const response = await fetch('my_module.wasm');
const buffer = await response.arrayBuffer();
const module = await WebAssembly.instantiate(buffer);
const handle_click = module.instance.exports.handle_click;
document.getElementById('myButton').addEventListener('click', handle_click);
在上面的例子中,首先通过fetch函数加载Wasm模块,然后通过WebAssembly.instantiate函数将其实例化。最后,可以通过module.instance.exports对象访问Wasm模块中导出的函数,并将其作为HTML元素事件的回调函数注册。