QML 提供了一个为编写 QML 程序而定制的 JavaScript 主机环境。该环境不同于浏览器提供的宿主环境或 Node.js 等服务器端 JavaScript 环境。例如,QML 不提供浏览器环境中常见的窗口对象或 DOM API。
5.5.1 Common Base
与浏览器或服务器端 JavaScript 环境一样,QML 运行时实现了 ECMAScript Language Specification 标准。这提供了对标准定义的所有内置类型和函数的访问,例如 Object、Array 和 Math。QML 运行时实现了标准的第 7 版。
Nullish Coalescing(Qt 5.15)和 Optional Chaining(Qt 6.2)也在 QML 运行时中实现。
QML 文档中没有明确记录标准 ECMAScript 内置函数。有关其使用的更多信息,请参阅 ECMA-262 第 7 版标准或众多在线 JavaScript 参考和教程站点之一,例如 W3Schools JavaScript Reference(JavaScript 对象参考部分)。许多站点专注于浏览器中的 JavaScript,因此在某些情况下,您可能需要仔细检查规范以确定给定的函数或对象是标准 ECMAScript 的一部分还是特定于浏览器环境。在上面的 W3Schools 链接的情况下,JavaScript 对象参考部分通常涵盖标准,而浏览器对象参考和 HTML DOM 对象参考部分是特定于浏览器的(因此不适用于 QML)。
5.5.2 类型注释和断言
函数声明可以并且应该包含类型注释。类型注释附加到参数声明和函数本身,用于注释返回类型。以下函数接受一个 int 和一个字符串参数,并返回一个 QtObject:
function doThings(a: int, b: string) : QtObject { ... }
类型注释有助于 Qt Creator 和 qmlint 等工具理解代码并提供更好的诊断。此外,它们使 C++ 中的函数更易于使用。更多信息,请参阅 Interacting with QML Objects from C++。
还可以使用类型断言将对象转换为不同的对象类型。如果对象实际上是给定的类型,则类型断言返回相同的对象。如果不是,则返回 null。在下面的代码片段中,我们在访问它的特定成员之前断言父对象是一个 Rectangle。
Item {
property color parentColor: (parent as Rectangle)?.color || "red"
}
如果父级实际上不是矩形,则可选链 (?.) 可避免抛出异常。在这种情况下,“red”被选为 parentColor。
5.5.3 QML 全局对象
QML JavaScript 宿主环境实现了许多宿主对象和函数,详见 QML Global Object。
5.5.4 JavaScript 对象和函数
QML 引擎支持的 JavaScript 对象、函数和属性的列表可以在 List of JavaScript Objects and Functions 中找到。
请注意,QML 对原生对象进行了以下修改:
此外,QML 还扩展了 instanceof 函数的行为,以允许针对 QML 类型进行类型检查。这意味着您可以使用它来验证变量确实是您期望的类型,例如:
var v = something();
if (!v instanceof Item) {
throw new TypeError("I need an Item type!");
}
...
5.5.5 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 文件包含带有“global”代码的外部 JavaScript 文件,则它会在仅包含外部文件本身和全局对象的范围内执行。也就是说,它将无法访问通常会访问的 QML 对象和属性。允许仅访问脚本局部变量的全局代码。这是有效全局代码的示例:
var colors = [ "red", "blue", "green", "orange", "purple" ];
//访问 QML 对象的全局代码将无法正确运行。
// Invalid global code - the "rootObject" variable is undefined
var initialPosition = { rootObject.x, rootObject.y }
由于 QML 环境尚未完全建立,因此存在此限制。要在环境设置完成后运行代码,请参阅 JavaScript in Application Startup Code。
- 在大多数情况下, this 值在 QML 中是未定义的。
从 JavaScript 绑定属性时支持 this 关键字。在 QML 绑定表达式、QML 信号处理程序和 QML 声明函数中,this 指的是作用域对象。在所有其他情况下,this 的值在 QML 中未定义。
要引用特定对象,请提供 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)
}
}