This is an integration approach for QWebChannel
with Vue.js v2
, consisted of a message broker
layer.
Qt
side should provide one or more QObject
which include all information shared with JS
side.
-
A
Cpp
function namedemitEmbeddedPageLoad
class WebBridge: public QObject { Q_OBJECT public slots: void emitEmbeddedPageLoad() { QMessageBox::information(NULL,"emitEmbeddedPageLoad", "I'm called by client JS!"); } }; WebBridge *webBridge = new WebBridge(); QWebChannel *channel = new QWebChannel(this); channel->registerObject('keyNamedContext', webBridge); view->page()->setWebChannel(channel);
-
In
JS
side, you should provide a init function whenQWebChannel
initialized.new QWebChannel(window.qt.webChannelTransport, function(channel) { const published = channel.objects.keyNamedContext Vue.prototype.$_bridge = published // This function calling will notify Qt server asynchronously published.emitEmbeddedPageLoad('', function(payload: string) { // This payload has included dispatcher name and its parameters. dispatch(payload) console.info(` Bridge load ! `) }) })
Advance: You can also create a process like these implementation for function calling or properties reading with abstract
namespace
. -
dispatch
function should include all navigation logic.
Once QWebChannel
initialized, dispatch
will be invoked when Cpp
function named emitEmbeddedPageLoad
return a value async notification. dispatch
function would play a navigator role in JS
side.
-
In
Qt
side, all entry point should be based on root path -https://<YOUR_HOST>/
. All navigation will be distributed byJS
side (vue-router
, a kind of front-end router) rather thanQt
.Qt
side would has more opportunities to focus on other business logic.-
When
Qt
side receives a initial message fromJS
side, it should return a value which syntax should be like:interface InitialProps { type: string payload: any }
// Actual value { type: [JS_SIDE_DISPATCHER_NAME], payload: [OPTIONAL_PAYLOAD] }
type
property will be used to invokedispatcher
in the dispatchersMap, thenpayload
property including any messages fromQt
side will passeddispatcher
.dispatcher
in the dispatchersMap plays anavigator
role in front-end, and developer should add navigation logic into here. This is all secrets about front-end navigation withoutQt
routing.Above all process has described how to initialize
Vue.js
app in theQWebEngine
, and how navigation works in theVue.js
withQWebEngine
. -
-
Be careful any external link and redirect uri from any external web site like
Alipay
online payment links. If you want to respect any redirect uri and prevent navigation from abovedispatch
function, you MUST provide non-root redirect uri (eg.https://<YOUR_HOST>/#/NOT_EMPTY_PATH
). You can find more details from dispatch function here.
If you want to push messages from JS
side to Qt
side, you can invoke the mapping of Qt
methods in JS
side directly:
channel.object[QObjectJSMappingKey].methodNameMappingFromQtSide(
payload,
callback
)
Enhance: the following logic is based on these implementation:
// A QObject named `QObjectJSMappingKey` (as an abstract namespace) in Qt/JS side
// in the vue instance
this.$$pusher.QObjectJSMappingKey({
action: 'QT_QOBJECT_KEY',
payload: 'CALLING_PAYLOAD'
})
Qt signal listener mechanism is a kind of good solution for communicate from Qt side to JS side. You may be wondering why we don't use signal mechanism directly to handle first frontend navigation? Because Qt side never known when frontend router is available until JS side push loaded
message to Qt side positively.
class WebBridge: public QObject {
Q_OBJECT
public slots:
void emitEmbeddedPageLoad();
// define your own signal
signals:
void signalMessageFromQt(const QString &str);
};
Always define all available signal listeners in config/bridge.ts:
interface SignalCallbacks {
[targetSignal: string]: Function
}
All signal would be handled automatically by these codes.