QML文档中的JavaScript表达式

描述在QML文档中JavaScript表达式有效的位置

由QML提供的JavaScript主机环境可以运行有效的标准JavaScript结构,如条件运算符、数组、变量设置和循环。除了标准的JavaScript属性外,QML全局对象还包括许多辅助方法,这些方法简化了构建用户界面和与QML环境的交互。

QML 提供的 JavaScript 环境比网页浏览器中的环境更为严格。例如,在 QML 中,你不能添加或修改 JavaScript 全局对象的成员。在常规的 JavaScript 中,可能会不小心通过使用未声明的变量来实现这一点。在 QML 中,这将抛出异常,因此所有局部变量必须显式声明。有关从 QML 执行的 JavaScript 代码的限制的完整描述,请参见 JavaScript 环境限制

QML文档的各个部分可以包含JavaScript代码:

  1. 属性绑定的主体。这些JavaScript表达式描述了QML对象属性之间的关系。当属性的依赖项发生变化时,属性也会根据指定的关系自动更新。

  2. Signal handlers 的主体。每当 QML 对象发出相关信号时,这些 JavaScript 语句会自动执行。

  3. 自定义方法 的定义。在 QML 对象体内定义的 JavaScript 函数将成为该对象的方法。

  4. 独立的 JavaScript 资源 (.js) 文件。这些文件实际上与 QML 文档是分开的,但它们可以被导入到 QML 文档中。导入文件中定义的函数和变量可以在属性绑定、信号处理程序和自定义方法中使用。

属性绑定中的JavaScript

在以下示例中,Rectangle 的 color 属性依赖于 TapHandler 的 pressed 属性。这种关系通过条件表达式来描述:

事实上,任何JavaScript表达式(无论多么复杂)都可以用于属性绑定定义,只要表达式的结果是一个可以分配给该属性类型的值。这包括副作用。然而,不鼓励使用复杂的绑定和副作用,因为它们可能会降低代码的性能、可读性和可维护性。

有两种定义属性绑定的方法:最常见的一种是在前面的示例中显示的,在属性初始化中。第二种(并且非常罕见)的方法是在命令式JavaScript代码中,将属性分配给从binding()函数返回的函数,如下所示:

请参阅属性绑定文档以获取有关如何定义属性绑定的更多信息,并参阅属性赋值与属性绑定文档以了解绑定与值赋值的区别。

信号处理程序中的JavaScript

QML对象类型可以在某些事件发生时发出信号。这些信号可以由信号处理函数处理,客户端可以定义这些函数来实现自定义的程序逻辑。

假设一个由Rectangle类型表示的按钮有一个TapHandler和一个文本标签。当用户按下按钮时,TapHandler会发出其tapped信号。客户端可以在onTapped处理程序中使用JavaScript表达式来响应信号。QML引擎根据需要执行在处理程序中定义的这些JavaScript表达式。通常,信号处理程序会绑定到JavaScript表达式以启动其他事件或分配属性值。

有关信号和信号处理程序的更多详细信息,请参考以下主题:

JavaScript 独立函数

程序逻辑也可以在JavaScript函数中定义。这些函数可以在QML文档中内联定义(作为自定义方法)或在导入的JavaScript文件中外部定义。

自定义方法中的JavaScript

可以在QML文档中定义自定义方法,并且可以从信号处理器、属性绑定或其他QML对象中的函数调用这些方法。这些方法通常被称为内联JavaScript函数,因为它们的实现包含在QML对象类型定义(QML文档)中,而不是在外部JavaScript文件中。

一个内联自定义方法的示例如下:

每当TapHandler发出tapped信号时,fibonacci函数就会运行。

注意

在QML文档中内联定义的自定义方法会暴露给其他对象,因此QML组件中根对象上的内联函数可以被组件外部的调用者调用。如果不希望这样,可以将方法添加到非根对象中,或者更优选地,将其写入外部JavaScript文件中。

请参阅QML对象属性文档,了解更多关于在QML中使用JavaScript定义自定义方法的信息。

在JavaScript文件中定义的函数

复杂的程序逻辑最好分离到一个单独的JavaScript文件中。这个文件可以使用import语句导入到QML中,就像QML 模块一样。

例如,前面示例中的fibonacci()方法可以移动到一个名为fib.js的外部文件中,并通过以下方式访问:

有关将外部JavaScript文件加载到QML中的更多信息,请阅读关于在QML中导入JavaScript资源的部分。

将信号连接到JavaScript函数

QML对象类型在发出信号时也会为其信号提供默认的信号处理程序,如前一节所述。然而,有时客户端希望在另一个QML对象发出信号时触发在QML对象中定义的函数。这种情况可以通过信号连接来处理。

通过调用信号的connect()方法并将JavaScript函数作为参数传递,可以将QML对象发出的信号连接到JavaScript函数。例如,以下代码将TapHandler的tapped信号连接到script.js中的jsFunction()

import QtQuick
import "script.js" as MyScript

Item {
    id: item
    width: 200; height: 200

    TapHandler {
        id: inputHandler
    }

    Component.onCompleted: {
        inputHandler.tapped.connect(MyScript.jsFunction)
    }
}
// script.js

function jsFunction() {
    console.log("调用了JavaScript函数!")
}

每当TapHandler的tapped信号发出时,就会调用jsFunction()

请参阅连接信号到方法和信号以获取更多信息。

应用程序启动代码中的JavaScript

在应用程序(或组件实例)启动时,偶尔需要运行一些命令式代码。虽然将启动脚本作为全局代码包含在外部脚本文件中很诱人,但这可能会带来严重的限制,因为QML环境可能尚未完全建立。例如,某些对象可能尚未创建,或者某些属性绑定可能尚未建立。有关全局脚本代码的确切限制,请参阅JavaScript环境限制

一个QML对象在其实例化完成时会发出Component.completed 附加信号。相应的Component.onCompleted处理程序中的JavaScript代码在对象实例化后运行。因此,编写应用程序启动代码的最佳位置是在顶级对象的Component.onCompleted处理程序中,因为当QML环境完全建立时,该对象会发出Component.completed

例如:

QML文件中的任何对象——包括嵌套对象和嵌套的QML组件实例——都可以使用这个附加属性。如果有多个onCompleted()处理程序在启动时执行,它们将按未定义的顺序依次运行。

同样,每个Component在被销毁之前都会发出一个destruction()信号。