JavaScript 宿主环境

QML 为编写 QML 应用程序提供定制的 JavaScript 宿主环境。这个环境与浏览器或像 Node.js 这样的服务器端 JavaScript 环境提供的宿主环境不同。例如,QML 不提供通常在浏览器环境中找到的 window 对象或 DOM API

公共基础

类似于浏览器或服务器端 JavaScript 环境,QML 运行时实现了 ECMAScript 语言规范 标准。这提供了对标准中定义的所有内置类型和函数的访问,例如 Object、Array 和 Math。QML 运行时实现了标准的第 7 版。

空值合并运算符 (??) (自 Qt 5.15 以来)和 可选链操作符 (?.) (自 Qt 6.2 以来)也被 QML 运行时所实现。

在 QML 文档中没有明确记录标准的 ECMAScript 内置。有关它们的使用信息,请参阅 ECMA-262 第 7 版标准或许多在线 JavaScript 参考 和教程网站,如 W3Schools JavaScript 参考(JavaScript 对象参考部分)。许多网站侧重于浏览器中的 JavaScript,所以在某些情况下您可能需要检查规范以确定给定的函数或对象是否是标准 ECMAScript 的一部分或特定于浏览器环境。在上面的 W3Schools 链接中,JavaScript Objects Reference 部分通常覆盖标准,而 Browser Objects ReferenceHTML DOM Objects Reference 部分是浏览器特定的(因此不适用于 QML)。

类型注释和断言

QML 文档中的函数声明可以,也应该包含类型注释。类型注释附加到参数的声明以及函数本身,用于注释返回类型。以下函数接受一个 int 和一个 string 参数,并返回一个 QtObject

function doThings(a: int, b: string) : QtObject { ... }

类型注释帮助工具如 Qt Creatorqmllint 理解代码并提供更好的诊断。此外,它们使函数更容易从 C++ 中使用。有关更多信息,请参阅 从 C++ 中与 QML 对象交互

类型断言(有时称为as-casts)也可以用于将对象转换为不同的对象类型。如果对象确实是给定类型,那么类型断言将返回相同的对象。如果不是,它将返回null。在以下代码片段中,我们在访问其特定成员之前断言parent对象是一个Rectangle

Item {
    property color parentColor: (parent as Rectangle)?.color || "red"
}

可选链接符(?:.)可以避免当父对象实际上不是矩形时抛出异常。在这种情况下,"red"将被选择作为parentColor

从Qt 6.7开始,在调用函数时始终强制执行类型注解。根据需要将值强制转换为所需类型。之前,类型注解被解释器和即时编译器忽略,但在编译到C++时由qmlcachegenqmlsc强制执行。这可能导致某些边缘 cases 的行为差异。为了明确请求解释器和JIT的旧行为,您可以在您的QML文档中添加以下内容

pragma FunctionSignatureBehavior: Ignored

QML全局对象

QML JavaScript宿主环境实现了一些宿主对象和函数,具体请参阅QML全局对象文档。

这些宿主对象和函数始终可用,不管是否导入了任何模块。

JavaScript对象和函数

可以在JavaScript对象和函数列表中找到QML引擎支持的JavaScript对象、函数和属性列表。

请注意,QML对原生对象进行了以下修改

  • String原形上添加了一个arg()函数。
  • DateNumber原形上添加了本地化的转换函数。

此外,QML还扩展了instanceof函数的行为,以允许对QML类型进行类型检查。这意味着您可以使用它来验证变量是否确实是您期望的类型,例如

var v = something();
if (!v instanceof Item) {
    throw new TypeError("I need an Item type!");
}

...

JavaScript环境限制

QML对JavaScript代码实施以下限制

  • .qml文件中编写的JavaScript代码不能修改全局对象。在.js文件中的JavaScript代码可以修改全局对象,并且这些修改在从导入时将对.qml文件可见。

    在QML中,全局对象是常量 - 现有的属性不能被修改或删除,并且不允许创建新的属性。

    大多数JavaScript程序都不会有意修改全局对象。然而,JavaScript自动声明未声明的变量是对全局对象的隐式修改,在QML中是不允许的。

    假设变量a不在作用域链中,以下代码在QML中是非法的

    // Illegal modification of undeclared variable
    a = 1;
    for (var ii = 1; ii < 10; ++ii)
        a = a * ii;
    console.log("Result: " + a);

    它可以轻易地修改成合法的代码。

    var a = 1;
    for (var ii = 1; ii < 10; ++ii)
        a = a * ii;
    console.log("Result: " + a);

    任何修改全局对象的尝试——无论是隐式的还是显式的——都会引起异常。如果未捕获,则会打印一个警告,其中包含有问题代码的文件和行号。

  • 全局代码在缩小的作用域中运行。

    在启动过程中,如果QML文件包括一个带有“全局”代码的外部JavaScript文件,它将在一个包含仅仅只是该外部文件和全局对象的作用域中执行。也就是说,它将无法访问它通常可以访问的QML对象和属性。

    仅访问脚本局部变量的全局代码是被允许的。这是一个有效全局代码的例子。

    var colors = [ "red", "blue", "green", "orange", "purple" ];

    访问QML对象的global代码将无法正常运行。

    // Invalid global code - the "rootObject" variable is undefined
    var initialPosition = { rootObject.x, rootObject.y }

    存在这种限制,因为QML环境尚未完全建立。要设置环境完毕后运行代码,请参阅应用程序启动代码中的JavaScript

  • 在QML的大多数上下文中,this的值是未定义的。

    当从JavaScript绑定属性时,支持this关键字。在QML绑定表达式、QML信号处理程序和QML声明的函数中,this指代作用域对象。在其他所有情况下,QML中this的值是未定义的。

    要引用特定对象,请提供id。例如

    Item {
        width: 200; height: 100
        function mouseAreaClicked(area) {
            console.log("Clicked in area at: " + area.x + ", " + area.y);
        }
        // This will pass area to the function
        MouseArea {
            id: area
            y: 50; height: 50; width: 200
            onClicked: mouseAreaClicked(area)
        }
    }

另请参阅作用域和命名解析

© 2024 Qt公司有限。本文件中包含的文档贡献版权属于其各自所有者。本文件提供的文档受自由软件基金会发布的GNU自由文档许可协议第1.3版的许可。Qt及相关商标是芬兰和/或其他国家的Qt公司的商标。商标