Defining JavaScript Resources In QML

QML应用程序的程序逻辑可以使用JavaScript定义. JavaScript代码既可以在QML文档中内联定义, 也可以分离为JavaScript文件(在QML中称为JavaScript Resources).

QML支持两种不同类型的JavaScript资源: 代码隐藏实现文件和共享(库)文件. 这两种JavaScript资源都可以由其他JavaScript资源imported, 也可以包含在QML modules中.

Code-Behind Implementation Resource

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

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

代码隐藏实现资源的示例如下:


  // MyButton.qml
  import QtQuick 2.0
  import "my_button_impl.js" as Logic // a new instance of this JavaScript resource is loaded for each instance of Button.qml

  Rectangle {
      id: rect
      width: 200
      height: 100
      color: "red"

      MouseArea {
          id: mousearea
          anchors.fill: parent
          onClicked: Logic.onClicked(rect)
      }
  }


  // my_button_impl.js
  var clickCount = 0;   // this state is separate for each instance of MyButton
  function onClicked(button) {
      clickCount += 1;
      if ((clickCount % 5) == 0) {
          button.color = Qt.rgba(1,0,0,1);
      } else {
          button.color = Qt.rgba(0,1,0,1);
      }
  }

一般来说, 简单的逻辑应该在QML文件中内联定义, 但更复杂的逻辑应该分离为代码背后的实现资源, 便于维护和可读.

共享的JavaScript资源(库)

默认情况下, 从QML导入的JavaScript文件与QML组件共享上下文. 这意味着JavaScript文件可以访问相同的QML对象, 并可以对其修改.

因此, 每次导入都必须具有这些文件的唯一副本. 上一节介绍了JavaScript文件的有状态导入. 然而, 有些JavaScript文件是无状态的, 更像是可重用的库, 因为它们提供了一组辅助函数, 不需要从导入它们的位置进行任何操作. 如果.pragma标记此类库, 则可以节省大量内存, 并加快QML组件的实例化速度, 如下例所示.


  // factorial.js
  .pragma library

  var factorialCount = 0;

  function factorial(a) {
      a = parseInt(a);

      // factorial recursion
      if (a > 0)
          return a * factorial(a - 1);

      // shared state
      factorialCount += 1;

      // recursion base-case.
      return 1;
  }

  function factorialCallCount() {
      return factorialCount;
  }

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

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

例如:


  // Calculator.qml
  import QtQuick 2.0
  import "factorial.js" as FactorialCalculator // this JavaScript resource is only ever loaded once by the engine, even if multiple instances of Calculator.qml are created

  Text {
      width: 500
      height: 100
      property int input: 17
      text: "The factorial of " + input + " is: " + FactorialCalculator.factorial(input)
  }

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