QML文档中的JavaScript表达式¶
描述在QML文档中JavaScript表达式有效的位置
由QML提供的JavaScript主机环境可以运行有效的标准JavaScript结构,如条件运算符、数组、变量设置和循环。除了标准的JavaScript属性外,QML全局对象还包括许多辅助方法,这些方法简化了构建用户界面和与QML环境的交互。
QML 提供的 JavaScript 环境比网页浏览器中的环境更为严格。例如,在 QML 中,你不能添加或修改 JavaScript 全局对象的成员。在常规的 JavaScript 中,可能会不小心通过使用未声明的变量来实现这一点。在 QML 中,这将抛出异常,因此所有局部变量必须显式声明。有关从 QML 执行的 JavaScript 代码的限制的完整描述,请参见 JavaScript 环境限制。
QML文档的各个部分可以包含JavaScript代码:
属性绑定的主体。这些JavaScript表达式描述了QML对象属性之间的关系。当属性的依赖项发生变化时,属性也会根据指定的关系自动更新。
Signal handlers 的主体。每当 QML 对象发出相关信号时,这些 JavaScript 语句会自动执行。
自定义方法 的定义。在 QML 对象体内定义的 JavaScript 函数将成为该对象的方法。
独立的 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()
信号。