在QML中定义JavaScript资源#

描述JavaScript文件如何用于QML

QML应用程序的程序逻辑可以用JavaScript定义。JavaScript代码可以定义在QML文档内联,或者分割到JavaScript文件中(在QML中称为 JavaScript 资源 )。

QML支持两种不同类型的JavaScript资源:后置实现文件和共享(库)文件。这两种类型的JavaScript资源都可以由其他JavaScript资源 导入,或者包含在 QML模块 中。

后置实现资源#

大多数导入到QML文档的JavaScript文件都是用于该QML文档的状态实现。在这些情况下,文档中定义的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文件是无状态的,并且更像是可重用的库,因为它们提供了一套辅助函数,不需要从导入的地方获取任何东西。您可以通过标记这类库来节省大量内存并加快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;
}

pragma声明的宣言必须出现在任何JavaScript代码(排除注释)之前。

请注意,多个QML文档可以导入 "factorial.js" 并调用它提供的阶乘(factorial)和调用次数(factorialCallCount)函数。导入JavaScript的状态在所有导入它的QML文档之间是共享的,因此,如果在从未调用阶乘函数的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)
}

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