QML属性绑定、内联函数和导入的JavaScript文件都运行在一个JavaScript作用域。作用域控制表达式可以访问哪些变量,以及当两个或多个名字冲突时,哪个,哪个变量优先。因为JavaScript的内建作用域机制非常简单,QML对其进行了加强,使其更加自然的适应QML语言的扩展。
1. JavaScript作用域
QML的作用域扩展并没有干扰JavaScript本身的作用域。
QtObject {
property int a: 3
property int b: 9
function addConstant(b) { //函数处理结果与QML对象的a和b属性无关
var a = 13
return b + a;
}
}
QML遵循JavaScript一般的作用域规则,在应用绑定时也是这样。
QtObject {
property int a
a: {var a = 12; a;} //给a属性绑定一个值12
}
每个在QML中的JavaScript表达式、函数或者文件都有它们任意一个里面声明的局部变量都不会和在另一个里面声明的局部变量冲突。
2. 元素名称和导入的JavaScript文件
QML文件包含了导入语句来定义元素名称和JavaScript文件,使其在文件中可见。除了在QML声明时使用,在访问附加属性和枚举值时JavaScript代码也会使用元素名称。在QML中import会影响每一个属性绑定、QML文件中的JavaScript函数以及那些嵌套的内联组件。
import QtQuick 2.4
import "code.js" as Code
ListView {
snapMode: ListView.SnapToItem
delegate: Component {
Text {
elide: Text.ElideMiddle
text:"A really, really long string that will require eliding."
color: Code.defaultColor()
}
}
}
3. 绑定作用域对象
属性绑定是在QML中最常见的JavaScript应用,关联了一个JavaScript表达式的结果和对象的一个属性。绑定对象所属的对象被称为绑定的作用域对象。QML为JavaScript引入了一个更加结构化、面向对象的方式,因此不再需要使用JavaScript的this属性。
当从绑定中访问附加属性是要非常小心,因为它们会与作用域对象交互。从概念上讲,附加属性在所有对象上都存在,即使它们只对这些对象的子集有影响。因此,非限定的附加属性的读取,总会得到作用域对象附加属性值。如PathView元素会向它的委托附加一个插值属性,这个插值属性依赖于在路径中具体的位置。因为PathView只会向委托的根元素附件这些属性,任何的子元素要访问这些属性都要明确限定根元素。
PathView {
delegate: Component{
Rectangle {
id: root
Image {
//如果Image元素忽略了root前缀,
//那么它就会在无意中访问在它自己上的未设置的PathView.scale附加属性
scale: root.PathView.scale
}
}
}
}
4. 组件作用域
在QML文件中的每一个组件都定义了一个逻辑作用域。每一个文件都至少有一个根组件,但是也可以拥有其他的内联自组件。组件的作用域是组件内的对象id和组件的根元素的属性的联合。
Item {
property string title
Text {
id: titleElement
text: "<b>" + title + "</b>"
font.pixelSize: 22
anchors.top: parent.top
}
Text {
text: titleElement.text
font.pixelSize: 18
anchors.bottom: parent.bottom
}
}
ID在QML中明确指定,所以它们总是优先于其他属性名称。如果在此例子中绑定的作用域对象也有一个titleElement属性,那么依然优先考虑id为titleElement,而不会把它当作一个属性。
5. 组件实例的层次
在QML中,组件实例将它们的作用域关联在一起形成了 一个作用域层次。组件实例可以直接访问其祖先的作用域。例如,使用内联子组件时, 它的组件作用域隐式的设置为了气外部组件作用域的孩子。
Item {
property color defaultColor: "blue"
ListView {
delegate: Component {
Rectangle{
color: defaultColor
}
}
}
}
组件实例层次允许委托组件的实例访问Item元素的defaultColor属性。当然,如果委托组件也有一个名为defaultColor的属性,那么将会优先访问它。
组件实例作用域层次可以扩展到非内联的组件。QML是一个动态作用域语言,依赖于在哪里被使用。
//TitlePage.qml文件
import QtQuick 2.4
Item {
property string title
TitleText {
size: 22
anchors.top: parent.top
}
TitleText {
size: 18
anchors.bottom: parnt.bottom
}
}
//TtileText.qml文件
import QtQuick 2.4
Text {
property int size
text: "<b>" + title + "</b>"
font.pixelSize: size
}
动态作用域是非常强大的,但是必须谨慎使用以避免QML代码的行为变得难以预料。一般情况下,它只用于两个组件已经通过其他方法紧密耦合的情况下。当构建可重用组件是,最好使用属性接口。
//TitlePage.qml文件
import QtQuick 2.4
Item {
id: root
property string title
TitleText {
size: 22
anchors.top: parent.top
}
TitleText {
title: root.title
size: 18
anchors.bottom: parnt.bottom
}
}
//TtileText.qml文件
import QtQuick 2.4
Text {
propterty string title
property int size
text: "<b>" + title + "</b>"
font.pixelSize: size
}
6. JavaScript全局对象
除了JavaScript全局对象的所有属性以外,QML还添加了一些自定义的扩展来更容易完成UI或者QML指定的任务。qml通过不允许元素、id和属性名称与全局对象的属性同名来防止冲突。