简短概括:
我写了一个库:js-bind,它可以接受任意数量的参数来轻松实现这一点:
using namespace std::placeholders;
using emscripten::val;
auto clickme_btn = val::global("document").call<val>("getElementById", string("clickme_btn"));
auto onclick = [](val event){ cout << "hello world ! " << endl; };
clickme_btn.set("onclick", js::bind(onclick, _1));
这个库是基于下面的宏元编程解释的一些内容。
详细答案:
你有不同的选择,比如emscripten ccall,但我认为更容易使用的是Embind。
例如,从C ++中绑定XMLHttpRequest的事件处理程序。
要启用它,您必须使用以下命令进行编译:
--bind -s NO_EXIT_RUNTIME=1
Emscripten:绑定独立函数
可以通过独立函数和单例轻松实现它,如下所示:
#include <iostream>
#include <emscripten.h>
#include <emscripten/bind.h>
#include <emscripten/val.h>
namespace xhr {
inline emscripten::val& singleton() {
using emscripten::val;
static val instance = val::global("XMLHttpRequest").new_();
return instance;
}
void on_load(emscripten::val event) {
std::cout << "Successful Query " << std::endl;
std::cout << "response is : " << singleton()["responseText"].as<std::string>() << std::endl;
}
void on_error(emscripten::val event) {
std::cout << "Error on query " << std::endl;
}
void on_progress(emscripten::val event) {
std::cout << "Progress on query " << std::endl;
std::cout << event["lengthComputable"].as<bool>() << ": " << event["loaded"].as<unsigned int>() / event["total"].as<unsigned int>() << std::endl;
}
using namespace emscripten;
EMSCRIPTEN_BINDINGS(xhr) {
function("on_load", &on_load);
function("on_error", &on_error);
function("on_progress", &on_progress);
}
}
int main(int argc, char** argv) {
using emscripten::val;
xhr::singleton().call<val>("open", std::string("GET"), std::string("http://127.0.0.1:8080/CMakeCache.txt"), true);
xhr::singleton().set("onload",val::module_property("on_load"));
xhr::singleton().set("onprogress",val::module_property("on_progress"));
xhr::singleton().set("onerror",val::module_property("on_error"));
xhr::singleton().call<val>("send");
return 0;
}
Emscripten:绑定成员函数
在C++中,我们通常使用std::bind回调函数。采用xhr示例,也可以以更简洁的方式实现:
#include <iostream>
#include <functional>
#include <memory>
#include <emscripten.h>
#include <emscripten/bind.h>
#include <emscripten/val.h>
class MiniXhr : public std::enable_shared_from_this<MiniXhr> {
using val = emscripten::val;
using url_t = std::string;
public:
void set_url(const url_t& url) { url_ = url; }
void GET();
void on_readystate(val event) {
std::cout << "ready " << std::endl;
std::cout << "xxhr::on_readystate: "
<< xhr["readyState"].as<size_t>() << " - " << url_ << " :: "
<< xhr["status"].as<size_t>() << ": "
<< xhr["statusText"].as<std::string>() << std::endl;
}
private:
url_t url_;
val xhr = val::global("XMLHttpRequest").new_();
};
using emscripten::class_;
EMSCRIPTEN_BINDINGS(MiniXhr) {
class_<MiniXhr>("MiniXhr")
.smart_ptr<std::shared_ptr<MiniXhr>>("shared_ptr<MiniXhr>")
.function("on_readystate", &MiniXhr::on_readystate)
;
class_<std::function<void(emscripten::val)>>("VoidValFunctor")
.constructor<>()
.function("opcall", &std::function<void(emscripten::val)>::operator());
}
void MiniXhr::GET() {
auto jsbind = [](val& target, const char* property, auto bind_expression ) {
std::function<void(emscripten::val)> functor = bind_expression;
auto functor_adapter = val(functor)["opcall"].call<val>("bind", val(functor));
target.set(property, functor_adapter);
};
jsbind(xhr, "onreadystatechange", std::bind(&MiniXhr::on_readystate, shared_from_this(), std::placeholders::_1));
xhr.call<val>("open", std::string("GET"), url_, true);
xhr.call<val>("send");
}
int main(int argc, char** argv) {
auto x = std::make_shared<MiniXhr>();
x->set_url("notfound.json");
x->GET();
return 0;
}