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)