JavaScript Expressions in QML Documents
QML提供的 JavaScript Host Environment 可以运行有效的标准JavaScript构造, 如条件运算符, 数组, 变量设置和循环. 除了标准的JavaScript属性外, QML全局对象还包括许多辅助方法, 这些方法简化了UI的构建和与QML环境的交互.
QML提供的JavaScript环境比web浏览器中的环境更严格. 例如, 在QML中, 你不能添加或修改JavaScript全局对象的成员. 在常规JavaScript中, 在不声明变量的情况下使用变量会执行此操作. 在QML中, 这将引发异常, 因此必须显式声明所有局部变量. 有关QML执行的JavaScript代码的限制的完整描述, 详见 JavaScript Environment Restrictions.
QML 文档中包含JavaScript代码的代码如下:
- The body of 属性绑定. 这些JavaScript表达式描述QML对象属性之间的关系. 当属性的依赖项发生更改时, 属性也会根据指定的关系自动更新.
- 信号处理程序. QML对象发出相关信号时, 会自动执行这些JavaScript语句.
- 自定义方法. 在QML对象中定义的JavaScript函数将成为该对象的方法.
- 独立的 JavaScript资源 (.js) 文件. 这些文件实际上与QML文档是分开的, 但它们可以导入到QML文档中. 在导入的文件中定义的函数和变量可以用于属性绑定、信号处理程序和自定义方法.
属性绑定中的JavaScript
如下所示, Rectangle的属性color
取决于MouseArea的属性pressed
. 它们的关系采用条件表达式描述:
import QtQuick 2.0 Rectangle { id: colorbutton width: 200; height: 80; color: mousearea.pressed ? "steelblue" : "lightsteelblue" MouseArea { id: mousearea anchors.fill: parent } }
事实上, 任何JavaScript表达式(无论多么复杂)都可以在属性绑定定义中使用, 只要表达式计算结果的类型可以分配给属性的值即可. 这种方式有副作用. 不鼓励使用复杂的绑定, 因为它们会降低代码的性能, 可读性和可维护性.
定义属性绑定有两种方法: 最常见的方法如前面的示例所示的在属性初始化中. 第二种(也是更罕见的)方法是从命令式JavaScript代码中为属性分配一个从Qt.binding()函数返回的函数, 如下所示:
import QtQuick 2.0 Rectangle { id: colorbutton width: 200; height: 80; color: "red" MouseArea { id: mousearea anchors.fill: parent } Component.onCompleted: { color = Qt.binding(function() { return mousearea.pressed ? "steelblue" : "lightsteelblue" }); } }
有关属性绑定的定义详见 property bindings, 有关如何绑定不同的值参见 Property Assignment versus Property Binding.
信号处理程序中的JavaScript
QML对象类型针对发生的某些事件发出信号. 这些信号可以由信号处理程序函数处理, 这些函数可以由客户端定义以实现自定义程序逻辑.
假设Rectangle类型表示的按钮有一个MouseArea和一个Text标签. 用户按下按钮时, MouseArea会发出pressed信号. 客户端可以使用JavaScript表达式对onPressed
处理程序中的信号做出反应. QML引擎根据需要执行处理程序中定义的这些JavaScript表达式. 通常, 信号处理程序绑定到JavaScript表达式, 以启动其他事件或分配属性值.
import QtQuick 2.0 Rectangle { id: button width: 200; height: 80; color: "lightsteelblue" MouseArea { id: mousearea anchors.fill: parent onPressed: { // arbitrary JavaScript expression label.text = "I am Pressed!" } onReleased: { // arbitrary JavaScript expression label.text = "Click Me!" } } Text { id: label anchors.centerIn: parent text: "Press Me!" } }
有关信号和信号处理程序的更多内容, 参见 Signal and Handler Event System , QML Object Attributes.
单独函数中的JavaScript
程序逻辑也可以在JavaScript函数中定义. 这些函数可以在QML文档中内联定义(作为自定义方法), 也可以在导入的JavaScript文件中外部定义.
自定义方法中的JavaScript
自定义方法可以在QML文档中定义, 也可以从信号处理程序, 属性绑定或其他QML对象中的函数中调用. 这种方法通常被称为内联JavaScript函数, 因为它们的实现包含在QML对象类型定义(QML文档)中, 而不是外部JavaScript文件中.
内联自定义方法的示例如下:
import QtQuick 2.0 Item { function factorial(a) { a = parseInt(a); if (a <= 0) return 1; else return a * factorial(a - 1); } MouseArea { anchors.fill: parent onClicked: console.log(factorial(10)) } }
MouseArea 发出 clicked
信号时, 调用fibonacci函数.
注意: QML文档中内联定义的自定义方法会暴露给其他对象, 因此QML组件中根对象上的内联函数可以由组件外部的使用方调用. 如果不希望这样做, 可以将该方法添加到非根对象中, 或者最好将其写入外部JavaScript文件中.
有关在QML中如何自定义方法. 参见 QML Object Attributes.
在JavaScript文件定义函数
非琐碎的程序逻辑最好分离到一个单独的JavaScript文件中. 与QML模块一样, 可以使用import
语句将文件导入QML.
例如, 前面示例中的factorial()
方法可以移动到名为factorial.js
的外部文件中, 并按如下方式访问:
import "factorial.js" as MathFunctions Item { MouseArea { anchors.fill: parent onClicked: console.log(MathFunctions.factorial(10)) } }
有关如何在QML中导入外部JavaScript文件, 参见 Importing JavaScript Resources in QML.
连接信号和JavaScript函数
如前一节所述, 发出信号的QML对象类型还为其信号提供默认的信号处理程序. 然而, 有时, 当另一个QML对象发出信号时, 客户端希望触发QML对象中定义的函数. 这种情况可以通过信号连接来处理.
QML对象发出的信号可以通过调用信号的connect()
方法, 并将JavaScript函数作为参数传递来连接到JavaScript函数. 例如, 以下代码将MouseArea的clicked
信号连接到script.js
中的jsFunction()
:
import QtQuick 2.0 import "script.js" as MyScript Item { id: item width: 200; height: 200 MouseArea { id: mouseArea anchors.fill: parent } Component.onCompleted: { mouseArea.clicked.connect(MyScript.jsFunction) } } | // script.js function jsFunction() { console.log("Called JavaScript function!") } |
MouseArea的 clicked
的信号发出时, 调用 jsFunction()
.
详见 Connecting Signals to Methods and Signals.
应用程序启动中的JavaScript
有时, 我们需要在应用程序(或组件实例)启动时, 运行一些命令式代码. 虽然将启动脚本作为全局代码包含在外部脚本文件中很诱人, 但这可能会有严重的限制, 因为QML环境可能尚未完全建立. 例如, 某些对象可能尚未创建, 或者某些属性绑定可能尚未建立. 有关全局脚本代码的确切限制, 参见 JavaScript Environment Restrictions.
QML对象在其实例化完成时, 发出Component.completed
附加信号. 相应Component.completed
处理程序中的JavaScript代码在对象实例化后运行. 因此, 编写应用程序启动代码的最佳位置是在顶级对象的Component.completed
处理程序中. 因为当QML环境完全建立时, 该对象会发出Component.completed
.
例如:
import QtQuick 2.0 Rectangle { function startupFunction() { // ... startup code } Component.onCompleted: startupFunction(); }
QML文件中的任何对象(包括嵌套对象和嵌套QML组件实例)都可以使用此附加属性. 如果在启动时要执行多个onCompleted()
处理程序,则它们的执行顺序未定义.
同样, 每个Component
在被销毁之前都会发出一个destruction()信号.