目录
QML 提供的 JavaScript 主机环境可以运行有效的标准 JavaScript表达式,例如条件运算符、数组、变量设置和循环。除了标准的 JavaScript 属性之外,QML 全局对象还包括许多帮助程序方法,这些方法简化了构建 UI 和与 QML 环境的交互。
QML提供的JavaScript环境比Web浏览器中的环境更严格。例如,在 QML 中,您不能添加或修改 JavaScript 全局对象的成员。在常规 JavaScript 中,可以通过使用变量而不声明它来意外执行此操作。在 QML 中,这将引发异常,因此必须显式声明所有局部变量。请参阅 JavaScript 环境限制,了解从 QML 执行的 JavaScript 代码限制的完整描述。JavaScript 主机环境|Qt QML 6.4.1https://doc.qt.io/qt-6/qtqml-javascript-hostenvironment.html#javascript-environment-restrictions
QML文档的各个部分可以包含JavaScript代码:
属性绑定的主体。这些 JavaScript 表达式描述了 QML 对象属性之间的关系。当属性的依赖项更改时,该属性也会根据指定的关系自动更新。
信号处理程序的主体。每当 QML 对象发出相关信号时,都会自动计算这些 JavaScript 语句。
自定义方法的定义。在 QML 对象主体中定义的 JavaScript 函数成为该对象的方法。
独立的 JavaScript 资源 (.js) 文件。这些文件实际上与 QML 文档是分开的,但它们可以导入到 QML 文档中。导入文件中定义的函数和变量可用于属性绑定、信号处理程序和自定义方法。
一、对属性值使用 JavaScript 表达式
Item {
width: Math.random()
height: width < 100 ? 100 : (width + 50) / 2
}
二、在 QML 中添加 JavaScript 函数
import QtQuick
Item {
id: container
width: 320
height: 480
function randomNumber() {
return Math.random() * 360;
}
function getNumber() {
return container.randomNumber();
}
TapHandler {
// This line uses the JS function from the item
onTapped: rectangle.rotation = container.getNumber();
}
Rectangle {
color: "#272822"
width: 320
height: 480
}
Rectangle {
id: rectangle
anchors.centerIn: parent
width: 160
height: 160
color: "green"
Behavior on rotation { RotationAnimation { direction: RotationAnimation.Clockwise } }
}
}
三、使用 JavaScript 文件
// myscript.js
function getRandom(previousValue) {
return Math.floor(previousValue + Math.random() * 90) % 360;
}
import QtQuick
import "myscript.js" as Logic
Item {
width: 320
height: 480
Rectangle {
color: "#272822"
width: 320
height: 480
}
TapHandler {
// This line uses the JS function from the separate JS file
onTapped: rectangle.rotation = Logic.getRandom(rectangle.rotation);
}
Rectangle {
id: rectangle
anchors.centerIn: parent
width: 160
height: 160
color: "green"
Behavior on rotation { RotationAnimation { direction: RotationAnimation.Clockwise } }
}
}
四、属性绑定中的 JavaScript
import QtQuick 2.12
Rectangle {
id: colorbutton
width: 200; height: 80;
color: inputHandler.pressed ? "steelblue" : "lightsteelblue"
TapHandler {
id: inputHandler
}
}
任何 JavaScript 表达式(无论多么复杂)都可以在属性绑定定义中使用,只要表达式的结果是其类型可以分配给属性的值。但是,不建议使用复杂的绑定和副作用,因为它们会降低代码的性能、可读性和可维护性。
有两种方法可以定义属性绑定:最常见的方法在前面的示例中的属性初始化中显示。第二种(也是更罕见的)方法是从命令式 JavaScript 代码中为属性分配一个从 Qt.binding() 函数返回的函数,如下所示:
import QtQuick 2.12
Rectangle {
id: colorbutton
width: 200; height: 80;
color: "red"
TapHandler {
id: inputHandler
}
Component.onCompleted: {
color = Qt.binding(function() { return inputHandler.pressed ? "steelblue" : "lightsteelblue" });
}
}
五、信号处理程序中的 JavaScript
QML 对象类型可以发出信号以响应发生的某些事件。这些信号可以由信号处理程序函数处理,客户端可以定义这些函数以实现自定义程序逻辑。
假设由矩形类型表示的按钮具有 TapHandler 和文本标签。当用户按下按钮时,点击处理程序会发出其点击信号。客户端可以使用 JavaScript 表达式对处理程序中的信号做出反应。QML 引擎根据需要执行处理程序中定义的这些 JavaScript 表达式。通常,信号处理程序绑定到 JavaScript 表达式以启动其他事件或分配属性值。
import QtQuick 2.12
Rectangle {
id: button
width: 200; height: 80; color: "lightsteelblue"
TapHandler {
id: inputHandler
onTapped: {
// arbitrary JavaScript expression
console.log("Tapped!")
}
}
Text {
id: label
anchors.centerIn: parent
text: inputHandler.pressed ? "Pressed!" : "Press here!"
}
}
六、将信号连接到 JavaScript 函数
发出信号的 QML 对象类型还为其信号提供默认信号处理程序。但是,有时客户端希望在另一个 QML 对象发出信号时触发在 QML 对象中定义的函数。这种情况可以通过信号连接来处理。QML 对象发出的信号可以通过调用信号的方法并将 JavaScript 函数作为参数传递来连接到 JavaScript 函数。例
// script.js
function jsFunction() {
console.log("Called JavaScript function!")
}
import QtQuick 2.12
import "script.js" as MyScript
Item {
id: item
width: 200; height: 200
TapHandler {
id: inputHandler
}
Component.onCompleted: {
inputHandler.tapped.connect(MyScript.jsFunction)
}
}
七、启动执行 JavaScript
有时需要在应用程序(或组件实例)启动时运行一些命令性代码。虽然将启动脚本作为全局代码包含在外部脚本文件中很诱人,但由于 QML 环境可能尚未完全建立,这可能会有严重的限制。例如,某些对象可能尚未创建,或者某些属性绑定可能尚未建立。
QML 对象在其实例化完成时发出附加的信号。相应处理程序中的 JavaScript 代码在对象实例化后运行。因此,编写应用程序启动代码的最佳位置是顶级对象的处理程序,因为此对象在完全建立 QML 环境时发出。
import QtQuick 2.0
Rectangle {
function startupFunction() {
// ... startup code
}
Component.onCompleted: startupFunction();
}
QML 文件中的任何对象(包括嵌套对象和嵌套的 QML 组件实例)都可以使用此附加属性。如果在启动时要执行多个处理程序,则它们将按未定义的顺序顺序运行。onCompleted()
同样,每个在被摧毁之前都会发出一个 destruction() 信号