Qt WebChannel JavaScript API

设置 JavaScript API

要通信与 QWebChannel or WebChannel ,客户端必须使用和设置 JavaScript API 提供通过 qwebchannel.js 。若客户端运行在 Qt WebEngine ,可以加载文件通过 qrc:///qtwebchannel/qwebchannel.js 。对于外部客户端,需要将文件拷贝到 Web 服务器。 然后实例化 QWebChannel 对象,并向其传递传输对象和回调函数,一旦通道初始化完成且已发布对象变为可用时,其就会被援引。

传输对象实现最少消息传递接口。它应是对象且具有 send() 函数,其接受字符串化 JSON 消息,并将消息传输到服务器侧 QWebChannelAbstractTransport 对象。此外,它的 onmessage 特性应被调用,当从自服务器收到消息时。另外,可以使用 WebSocket 去实现接口。

注意:JavaScript QWebChannel 对象应该被构造一旦传输对象可完整操作。对于 WebSocket,意味着应该创建 QWebChannel 在套接字的 onopen 处理程序。查看 Qt WebChannel 独立范例 看如何做到这点。

与 QObject 交互

一旦回调传递给 QWebChannel 对象被援引,通道已完成初始化且 HTML 客户端可访问所有已发布对象凭借 channel.objects 特性。因此,假定采用标识符 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 的类型系统,只有单 number 类型能最好映射到 C++ double。当重载仅在像 number 参数的类型上有所不同时, QWebChannel 将始终选取最佳匹配 JavaScript number 类型的重载。当连接到被重载信号时, QWebChannel 默认情况下,客户端只会连接到该名称的第一信号重载。此外,可以明确请求方法和信号的重载通过其完整 QMetaMethod 签名。假定有以下 QObject 子类在 C++ 侧:

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)