QML 程序的逻辑可以在 JavaScript 中定义。JavaScript 代码可以在 QML 文档中内嵌定义,也可以分成 JavaScript 文件(在 QML 中称为 JavaScript 资源)。

QML 支持两种 JavaScript 资源:代码隐藏实现文件、共享库文件。

5.3.1 第一种:代码隐藏实现资源

大多数导入 QML 文档的 JavaScript 文件都是导入它们的 QML 文档的有状态实现。在这些情况下,文档中定义的 QML 对象类型的每个实例都需要 JavaScript 对象和状态的单独副本,以便正确运行。

导入 JavaScript 文件时的默认行为是为每个 QML 组件实例提供一个唯一的、独立的副本。如果该 JavaScript 文件没有使用 .import语句导入任何资源或模块,则其代码将在与 QML 组件实例相同的范围内运行,因此可以访问和操作在该 QML 组件中声明的对象和属性。否则,它将拥有自己唯一的作用域,如果需要,QML 组件的对象和属性应作为参数传递给 JavaScript 文件的函数。

示例:

  1. // MyButton.qml
  2. import QtQuick 2.0
  3. import "my_button_impl.js" as Logic // A new instance of this JavaScript resource
  4. // is loaded for each instance of Button.qml.
  5. Rectangle {
  6. id: rect
  7. width: 200
  8. height: 100
  9. color: "red"
  10. MouseArea {
  11. id: mousearea
  12. anchors.fill: parent
  13. onClicked: Logic.onClicked(rect)
  14. }
  15. }
  16. // my_button_impl.js
  17. var clickCount = 0; // this state is separate for each instance of MyButton
  18. function onClicked(button) {
  19. clickCount += 1;
  20. if ((clickCount % 5) == 0) {
  21. button.color = Qt.rgba(1,0,0,1);
  22. } else {
  23. button.color = Qt.rgba(0,1,0,1);
  24. }
  25. }

一般来说,在 QML 文件中定义简单逻辑,而复杂逻辑应该分离到代码隐藏的实现资源中,以提高可维护性和可读性。

5.3.2 共享 JavaScript 资源(库)

默认情况下,从 QML 导入的 JavaScript 文件与 QML 组件共享它们的上下文。这意味着 JavaScript 文件可以访问相同的 QML 对象并可以修改它们。因此,每次导入都必须具有这些文件的唯一副本。

上一节介绍了 JavaScript 文件的有状态导入。然而,一些 JavaScript 文件是无状态的,更像是可重用的库,因为它们提供了一组不需要从它们导入的地方获取任何东西的辅助函数。如果使用特殊的编译指示标记此类库,则可以节省大量内存并加快 QML 组件的实例化,如下例所:

  1. // factorial.js
  2. .pragma library
  3. var factorialCount = 0;
  4. function factorial(a) {
  5. a = parseInt(a);
  6. // factorial recursion
  7. if (a > 0)
  8. return a * factorial(a - 1);
  9. // shared state
  10. factorialCount += 1;
  11. // recursion base-case.
  12. return 1;
  13. }
  14. function factorialCallCount() {
  15. return factorialCount;
  16. }

pragma 声明必须出现在除注释之外的任何 JavaScript 代码之前。

请注意,多个 QML 文档可以导入“factorial.js”并调用它提供的 factorial 和 factorialCallCount 函数。JavaScript 导入的状态在导入它的 QML 文档之间共享,因此在从不调用 factorial 函数的 QML 文档中调用时,factorialCallCount 函数的返回值可能是非零的。

例如:

  1. // Calculator.qml
  2. import QtQuick 2.0
  3. import "factorial.js" as FactorialCalculator // This JavaScript resource is only
  4. // ever loaded once by the engine,
  5. // even if multiple instances of
  6. // Calculator.qml are created.
  7. Text {
  8. width: 500
  9. height: 100
  10. property int input: 17
  11. text: "The factorial of " + input + " is: " + FactorialCalculator.factorial(input)
  12. }

由于它们是共享的,.pragma 库文件不能直接访问 QML 组件实例对象或属性,尽管 QML 值可以作为函数参数传递。