在QML中导入JavaScript资源

描述如何在QML文档中导入和使用JavaScript资源

JavaScript 资源 可以被 QML 文档和其他 JavaScript 资源导入。JavaScript 资源可以通过相对或绝对 URL 导入。在相对 URL 的情况下,位置是相对于包含导入的 QML 文档JavaScript 资源 的位置解析的。如果脚本文件无法访问,将会发生错误。如果 JavaScript 需要从网络资源获取,组件的 status 将被设置为“加载中”,直到脚本下载完成。

JavaScript 资源也可以导入 QML 模块和其他 JavaScript 资源。JavaScript 资源中的导入语句的语法与 QML 文档中的导入语句略有不同,下面将详细记录。

从QML文档导入JavaScript资源

一个QML文档可以使用以下语法导入JavaScript资源:

import "ResourceURL" as Qualifier

例如:

import "jsfile.js" as Logic

导入的JavaScript资源总是使用“as”关键字进行限定。JavaScript资源的限定符必须以大写字母开头,并且必须是唯一的,因此限定符和JavaScript文件之间总是一对一的映射关系。(这也意味着限定符不能命名为与内置JavaScript对象相同的名称,例如DateMath)。

在导入的JavaScript文件中定义的函数可以通过"Qualifier.functionName(params)"语法提供给导入的QML文档中定义的对象使用。JavaScript资源中的函数可以接受参数,这些参数的类型可以是任何QML值类型或对象类型,也可以是普通的JavaScript类型。当从QML调用这些函数时,正常的数据类型转换规则将适用于参数和返回值。

JavaScript资源中的导入

QtQuick 2.0中,增加了支持,允许JavaScript资源导入其他JavaScript资源以及使用标准QML导入语法的变体导入QML类型命名空间(其中所有先前描述的规则和限定条件都适用)。

由于JavaScript资源能够以这种方式在QtQuick 2.0中导入另一个脚本或QML模块,因此定义了一些额外的语义:

  • 带有导入的脚本不会从导入它的QML文档继承导入(例如,访问Component.errorString将会失败)

  • 没有导入的脚本将从导入它的QML文档继承导入(例如,访问Component.errorString将会成功)

  • 共享脚本(即定义为 .pragma library)不会从任何 QML 文档继承导入,即使它没有导入其他脚本或模块

第一个语义在概念上是正确的,考虑到一个特定的脚本可能会被任意数量的QML文件导入。第二个语义为了向后兼容的目的而保留。第三个语义与当前共享脚本的语义保持不变,但在这里针对新可能出现的情况(脚本导入其他脚本或模块)进行了澄清。

从另一个JavaScript资源导入JavaScript资源

一个JavaScript资源可以以下列方式导入另一个:

import * as MathFunctions from "factorial.mjs";

或者:

.import "filename.js" as Qualifier

前者是用于导入ECMAScript模块的标准ECMAScript语法,仅在以mjs文件扩展名表示的ECMAScript模块内有效。后者是由QML引擎提供的JavaScript扩展,也可以在非模块中使用。作为被ECMAScript标准取代的扩展,不鼓励使用它。

当以这种方式导入JavaScript文件时,它会带有一个限定符导入。然后,导入脚本中的函数可以通过限定符访问(即,作为Qualifier.functionName(params))。

有时希望在导入上下文中使函数可用而无需限定它们。在这种情况下,应使用ECMAScript模块和JavaScript import语句,而不使用as限定符。

例如,下面的QML代码左侧调用了script.mjs中的showCalculations(),而它又可以调用factorial.mjs中的factorial(),因为它已经使用import包含了factorial.mjs

import QtQuick
import "script.mjs" as MyScript

Item {
    width: 100; height: 100

    MouseArea {
        anchors.fill: parent
        onClicked: {
            MyScript.showCalculations(10)
            console.log("从QML调用factorial():",
                MyScript.factorial(10))
        }
    }
}
// script.mjs
import { factorial } from "factorial.mjs"
export { factorial }

export function showCalculations(value) {
    console.log(
        "从script.js调用factorial():",
        factorial(value));
}
// 阶乘.mjs
export function factorial(a) {
    a = parseInt(a);
    if (a <= 0)
        return 1;
    else
        return a * factorial(a - 1);
}

include() 函数在不使用 ECMAScript 模块且不限定导入的情况下,从一个 JavaScript 文件包含另一个文件。它使另一个文件中的所有函数和变量在当前文件的命名空间中可用,但忽略该文件中定义的所有编译指示和导入。这不是一个好主意,因为函数调用不应修改调用者的上下文。

include() 已被弃用,应避免使用。它将在未来的 Qt 版本中被移除。

从JavaScript资源导入QML模块

一个JavaScript资源可以以下列方式导入一个QML模块:

.import TypeNamespace MajorVersion.MinorVersion as Qualifier

下面你可以看到一个示例,该示例还展示了如何在javascript中使用从模块导入的QML类型:

.import Qt.test 1.0 as JsQtTest

var importedEnumValue = JsQtTest.MyQmlObject.EnumValue3

特别是,这可能有助于访问通过单例类型提供的功能;有关更多信息,请参见QML_SINGLETON

默认情况下,您的 JavaScript 资源可以访问导入该资源的组件的所有导入。如果它被声明为无状态库(使用 .pragma library)或包含显式的 .import 语句,则它无法访问组件的导入。

注意

.import 语法不适用于 WorkerScript 中使用的脚本