1.需求:产品需要嵌入某路由器控制界面,但是想隐藏路由器的品牌信息。
先看看效果图:
JS注入前:
JS注入后
2.C++代码,请看代码注释:
#include <QApplication>
#include <QWebEngineView>
#include <QPushButton>
#include <QTimer>
#include <QFile>
#include <QWebEngineScript>
#include <QIODevice>
#include <QWebEngineProfile>
#include <QWebEngineScriptCollection>
#include <QWebEngineSettings>
#include <QWebEngineCookieStore>
QUrl commandLineUrlArgument()
{
const QStringList args = QCoreApplication::arguments();
for (const QString& arg : args.mid(1)) {
if (!arg.startsWith(QLatin1Char('-')))
return QUrl::fromUserInput(arg);
}
return QUrl(QStringLiteral("http://tplogin.cn/login.htm"));
}
int main(int argc, char* argv[])
{
QCoreApplication::setOrganizationName("QtExamples");
QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
QApplication app(argc, argv);
qputenv("QTWEBENGINE_REMOTE_DEBUGGING", "7777"); // 设置远程调试环境变量
QWebEngineView view;
view.setUrl(commandLineUrlArgument());
QWebEngineProfile* engineProfile = view.page()->profile();
engineProfile->clearHttpCache(); // 清理缓存
engineProfile->clearAllVisitedLinks(); // 清理浏览记录
engineProfile->setPersistentCookiesPolicy(QWebEngineProfile::NoPersistentCookies);// 会话和持久性cookie都存储在内存中
engineProfile->setHttpCacheType(QWebEngineProfile::NoCache);// 禁用内存和磁盘缓存。
QWebEngineCookieStore* pCookie = engineProfile->cookieStore();
pCookie->deleteAllCookies(); // 清理cookie
pCookie->deleteSessionCookies(); // 清理会话cookie
// 在DocumentReady的时候注入js代码
QFile file("test.js");
if (file.open(QIODevice::ReadOnly))
{
QString content = file.readAll();
file.close();
QWebEngineScript script;
script.setSourceCode(content);
script.setWorldId(QWebEngineScript::MainWorld);
script.setInjectionPoint(QWebEngineScript::DocumentReady);
view.page()->profile()->scripts()->insert(script);
}
// QWebEngineView开始加载的时候
QObject::connect(&view, &QWebEngineView::loadStarted, [&view] {
qDebug() << "loadStarted";
});
// QWebEngineView加载完成的时候
QObject::connect(&view, &QWebEngineView::loadFinished, [&view] {
// 注意此处需要延时再执行js操作,否则获取不到文档对象。
QTimer::singleShot(500, [&view] {
qDebug() << "loadFinished" << view.title();
view.page()->runJavaScript("$('#menu-advanced-running-status-li a').click()");
view.show();
});
});
view.resize(1024, 750);
view.show();
return app.exec();
}
3.test.js代码
// test.js
// 获取head标签,插入style标签,此处css的作用是隐藏界面上的一系列元素
var head = document.getElementsByTagName('head')[0];
var style = document.createElement('style');
style.type = 'text/css';
head.appendChild(style);
var css = "\
body > div.login-banner > a {display: none;}\r\n\
body > div.login-banner > h1 {padding-left: 156px;}\r\n\
body > div.top-banner {display: none;}\r\n\
body > div.user-info {display: none;}\r\n\
body > div.top-tip {display: none;}\r\n\
#menu-advanced-homepage-li {display: none;}\r\n\
#func-advanced > div.home-page-main > div.wireless-info {display: none;}\r\n\
#func-advanced > div.home-page-main > div.system-topo-info > div.system_info_panel > div.content > div:nth-child(4) {display: none;}\r\n\
#menu-advanced-ap-manager-li {display: none;}\r\n\
#menu-advanced-mesh-manage-li {display: none;}\r\n\
#menu-advanced-advanced-li > div > ul > li:nth-child(5) {display: none;}\r\n\
#menu-advanced-sys-tools-li > div > ul > li.sec.sec-fst {display: none;}\r\n\
#menu-advanced-sys-tools-li > div > ul > li:nth-child(6) {display: none;}\r\n\
#menu-wizard {display: none;}\r\n\
#menu-footer {display: none;}\r\n\
";
style.innerHTML = css;
4.注意QWebEngineView::loadFinished信号后延时了500ms再去执行js,否则获取不到文档对象。此处有个较为优雅的处理方法,就是在注入的js中再调用C++的方法,我的其它项目这样做过。