【问题标题】:PyQt5 How To Use JavaScript ModulesPyQt5 如何使用 JavaScript 模块
【发布时间】:2021-11-20 06:51:20
【问题描述】:

在我的应用程序中,我使用 PyQt5 创建了一个窗口并加载了一个 HTML 源代码。我想在需要使用 JavaScript 模块的项目中使用 ThreeJS。但是我似乎没有让模块在我的设置中工作:

这很好用:<script src="js/main.js"></script>

这不是:<script type="module" src="js/main.js"></script>

这里有什么问题?我是否需要在 PyQt5 中做一些额外的事情来启用 JavaScript 模块。

如果没有 JavaScript 模块,使用 ThreeJS 会非常困难,我该如何解决这个问题?

编辑:这是我正在使用的 PyQt5 代码:

import sys
import os
from PyQt5.QtCore import *
from PyQt5.QtWidgets import *
from PyQt5.QtWebEngineWidgets import *

class MainWindow(QMainWindow):
    def __init__(self):
        super(MainWindow, self).__init__()
        self.browser = QWebEngineView()
        config_name = 'data_files/init.html'
        if getattr(sys, 'frozen', False):
            application_path = os.path.dirname(sys.executable)
        elif __file__:
            application_path = os.path.dirname(__file__)
        config_path = os.path.join(application_path, config_name)
        self.browser.load(QUrl().fromLocalFile(config_path))
        self.setCentralWidget(self.browser)
        self.showMaximized()


app = QApplication(sys.argv)
QApplication.setApplicationName('v0.1')
window = MainWindow()
app.exec_()

这是html:

<body>
    <script src="js/main.js"></script>
    <div id="myText" style="opacity:0">Hello World</div>
</body>¨

这是javaScript:

window.addEventListener("load", () => {
    document.getElementById("myText").style.opacity = "1"
})

JavaScript 仅在脚本不是模块时有效,当使用 type="module" 时没有任何反应,我的元素的不透明度不会改变。

【问题讨论】:

  • 我已经添加了 PyQt5 代码,希望对您有所帮助。
  • 不,这还不够。我需要 .html 和 js 才能分析错误在哪里。
  • 你好,我又更新了。我希望现在情况好些了。很抱歉没有提供所有必要的代码,我认为它没有那么相关。感谢您帮助我!

标签: javascript python module pyqt5


【解决方案1】:

解释:

正如the docs 指出的那样:

您需要注意本地测试 — 如果您尝试在本地加载 HTML 文件(即使用 file:// URL),由于 JavaScript 模块的安全要求,您会遇到 CORS 错误。您需要通过服务器进行测试。

如果您使用本地文件,则无法访问这些模块,因此您会收到错误消息:

js: Failed to load module script: The server responded with a non-JavaScript MIME type of "". Strict MIME type checking is enforced for module scripts per HTML spec.

解决方案:

在这种情况下,有 2 个选项:

1。本地服务器

实现一个服务器,例如使用aiohttp + qasync:

import asyncio
import functools
import os
from pathlib import Path
import sys

from aiohttp import web

from PyQt5.QtCore import QUrl
from PyQt5.QtWidgets import QMainWindow
from PyQt5.QtWebEngineWidgets import QWebEngineView

import qasync
from qasync import QApplication


application_path = (
    Path(sys.executable).resolve().parent
    if getattr(sys, "frozen", False)
    else Path(__file__).resolve().parent
)


class MainWindow(QMainWindow):
    def __init__(self):
        super(MainWindow, self).__init__()
        self.browser = QWebEngineView()

        config_name = "/data_files/init.html"
        url = QUrl("http://localhost:4000")
        url.setPath(config_name)
        self.browser.load(url)
        self.setCentralWidget(self.browser)
        self.showMaximized()


async def main():
    def close_future(future, loop):
        loop.call_later(10, future.cancel)
        future.cancel()

    loop = asyncio.get_event_loop()
    future = asyncio.Future()

    qt_app = QApplication.instance()
    if hasattr(qt_app, "aboutToQuit"):
        getattr(qt_app, "aboutToQuit").connect(
            functools.partial(close_future, future, loop)
        )

    app = web.Application()
    app.router.add_static("/", application_path, show_index=True)
    runner = web.AppRunner(app)
    await runner.setup()
    site = web.TCPSite(runner, "localhost", 4000)
    await site.start()

    view = MainWindow()
    view.show()

    await future
    await runner.cleanup()
    return True


if __name__ == "__main__":
    try:
        qasync.run(main())
    except asyncio.exceptions.CancelledError:
        sys.exit(0)

2。自定义 QWebEngineUrlSchemeHandler

import sys
import os
from PyQt5.QtCore import QCoreApplication, QUrl, QFile, QFileInfo, QMimeDatabase
from PyQt5.QtWidgets import QApplication, QMainWindow
from PyQt5.QtWebEngineCore import (
    QWebEngineUrlScheme,
    QWebEngineUrlSchemeHandler,
    QWebEngineUrlRequestJob,
)
from PyQt5.QtWebEngineWidgets import QWebEngineView


application_path = (
    os.path.dirname(sys.executable)
    if getattr(sys, "frozen", False)
    else os.path.dirname(__file__)
)


class QtSchemeHandler(QWebEngineUrlSchemeHandler):
    def requestStarted(self, job):
        request_method = job.requestMethod()
        if request_method != b"GET":
            job.fail(QWebEngineUrlRequestJob.RequestDenied)
            return

        request_url = job.requestUrl()
        request_path = request_url.path()
        file = QFile(application_path + request_path)
        file.setParent(job)
        job.destroyed.connect(file.deleteLater)
        if not file.exists() or file.size() == 0:
            print(f"resource '{request_path}' not found or is empty")
            job.fail(QWebEngineUrlRequestJob.UrlNotFound)
            return

        file_info = QFileInfo(file)
        mime_database = QMimeDatabase()
        mime_type = mime_database.mimeTypeForFile(file_info)
        job.reply(mime_type.name().encode(), file)


class MainWindow(QMainWindow):
    def __init__(self):
        super(MainWindow, self).__init__()
        self.browser = QWebEngineView()
        self.scheme_handler = QtSchemeHandler()
        self.browser.page().profile().installUrlSchemeHandler(
            b"qt", self.scheme_handler
        )
        filename = "/data_files/init.html"
        url = QUrl("qt://main")
        url.setPath(filename)
        self.browser.load(url)
        self.setCentralWidget(self.browser)


if __name__ == "__main__":

    scheme = QWebEngineUrlScheme(b"qt")
    scheme.setFlags(QWebEngineUrlScheme.CorsEnabled)
    QWebEngineUrlScheme.registerScheme(scheme)
    app = QApplication(sys.argv)
    QApplication.setApplicationName("v0.1")
    window = MainWindow()
    window.show()
    app.exec_()

文件结构:

├── data_files
│   ├── init.html
│   └── js
│       └── main.js
└── main.py

【讨论】:

  • 谢谢,我会尽力实现你所描述的。有什么理由让我更喜欢方法 1 而不是方法 2 - 例如,我的“网站”只能在本地访问(使用可执行文件),所以这可能是决定的因素吗?
  • 我最终使用了Custom QWebEngineUrlSchemeHandler
【解决方案2】:

如果你 add Dev Tools 到你的项目,你会看到 JavaScript 错误..

就您而言,问题是:

您也可以查看this link 来解决您的问题。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2021-07-14
    • 2021-12-19
    • 1970-01-01
    • 1970-01-01
    • 2011-08-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多