Qt WebChannel JavaScript API#
此页面解释了如何在HTML客户端中使用JavaScript QWebChannel
API。
设置JavaScript API#
要与一个 QWebChannel
或 WebChannel 通信,客户端必须使用并设置由 qwebchannel.js
提供的JavaScript API。对于在Qt WebEngine中运行的客户端,您可以通过 qrc:///qtwebchannel/qwebchannel.js
加载该文件。对于外部客户端,您需要将该文件复制到您的Web服务器上。然后实例化一个 QWebChannel
对象,并将传输对象和回调函数传递给它,该回调函数将在通道初始化完成并且已发布对象可用时被调用。可选的第三个参数包含转换包装函数的数组或单个函数。
传输对象实现了一个最小化的消息传递接口。它应该是一个具有一个 send()
函数的对象,该函数接收一个字符串化的JSON消息并将其传输到服务器端的 QWebChannelAbstractTransport
对象。此外,当接收到来自服务器的消息时,应该调用其 onmessage
属性。或者,您可以使用WebSocket来实现该接口。
请注意,必须在传输对象完全运行后构建JavaScript QWebChannel
对象。在WebSocket的情况下,这意味着您应该在该socket的 onopen
处理器中创建 QWebChannel
。请查看 Qt WebChannel 独立示例 了解如何实现此操作。
转换器包装函数可以是带有内置转换器名称的字符串,或者是一个用户提供的函数,该函数将处理的对象作为参数,并返回结果类型或未定义(如果函数不适用)。如果返回未定义,则处理下一个转换器。如果没有转换器返回除了未定义之外的值,则正常进行处理。“日期”是唯一的当前内置转换器函数。它接受包含ISO 8601日期的字符串,如果语法正确且日期有效,则返回一个新的日期对象。
与QObject交互#
一旦调用传递给QWebChannel
对象的回调函数,通道初始化完成,所有发布的对象都可通过channel.objects
属性被HTML客户端访问。因此,假设已使用“foo”标识符发布了一个对象,那么我们可以像以下示例所示那样与它交互。请注意,HTML客户端和QML/C++服务器之间的所有通信都是异步的。属性在HTML侧被缓存。此外,请记住,只有可以转换为JSON的QML/C++数据类型才能正确进行(反)序列化,因此可以供HTML客户端访问。
new QWebChannel(yourTransport, function(channel) { // Connect to a signal: channel.objects.foo.mySignal.connect(function() { // This callback will be invoked whenever the signal is emitted on the C++/QML side. console.log(arguments); }); // To make the object known globally, assign it to the window object, i.e.: window.foo = channel.objects.foo; // Invoke a method: foo.myMethod(arg1, arg2, function(returnValue) { // This callback will be invoked when myMethod has a return value. Keep in mind that // the communication is asynchronous, hence the need for this callback. console.log(returnValue); }); // Read a property value, which is cached on the client side: console.log(foo.myProperty); // Writing a property will instantly update the client side cache. // The remote end will be notified about the change asynchronously foo.myProperty = "Hello World!"; // To get notified about remote property changes, // simply connect to the corresponding notify signal: foo.myPropertyChanged.connect(function() { console.log(foo.myProperty); }); // One can also access enums that are marked with Q_ENUM: console.log(foo.MyEnum.MyEnumerator); });
重载方法和信号#
当发布具有重载方法的QObject
时,QWebChannel
会将方法调用解析为最佳匹配。请注意,由于JavaScript的类型系统,只有一个“数字”类型,它最适合映射到一个C++“双精度浮点数”。当重载方法仅在不同类型的参数类型上有所不同时,QWebChannel
将始终选择最匹配JavaScript“数字”类型的那种重载。当你连接到重载的信号时,QWebChannel
客户端会默认仅连接到该名称的第一个信号重载。此外,方法和支持信号的完整QMetaMethod
签名可以显式请求。假设我们在C++侧有以下QObject
子类
class Foo : public QObject { Q_OBJECT slots: void foo(int i); void foo(double d); void foo(const QString &str); void foo(const QString &str, int i); signals: void bar(int i); void bar(const QString &str); void bar(const QString &str, int i); };
然后,您可以在JavaScript端这样与这个类交互
// methods foo.foo(42); // will call the method named foo which best matches the JavaScript number parameter, i.e. foo(double d) foo.foo("asdf"); // will call foo(const QString &str) foo.foo("asdf", 42); // will call foo(const QString &str, int i) foo["foo(int)"](42); // explicitly call foo(int i), *not* foo(double d) foo["foo(QString)"]("asdf"); // explicitly call foo(const QString &str) foo["foo(QString,int)"]("asdf", 42); // explicitly call foo(const QString &str, int i) // signals foo.bar.connect(...); // connect to first signal named bar, i.e. bar(int i) foo["bar(int)"].connect(...); // connect explicitly to bar(int i) foo["bar(QString)"].connect(...); // connect explicitly to bar(const QString &str) foo["bar(QString,int)"].connect(...); // connect explicitly to bar(const QString &str, int i)