QML作用域个人认为是一个比较复杂的主题。本文将结合自己理解,对QML文档作用域及JavaScript作用域分别进行介绍。
一、QML文档作用域
每个QML文档定义了一个作用域,这个作用域包含了:根对象所有属性以及文档中包含的所有id属性。通过以下示例进一步说明文档作用域:
Item {
property string title
Text {
id: titletype
text: "<b>" + title + "</b>"
font.pixelSize: 22
anchors.top: parent.top
}
Text {
text: titletype.text
font.pixelSize: 18
anchors.bottom: parent.bottom
}
}
在以上例子中,包含了一个QML文档,这个文档中定义了一个对象类型。在这类型定义中,包含了一个Item类型的根对象。以及两个Text类型的子对象。因此,这个文档定义的逻辑作用域为:Item类型的所有属性、title属性以及第一个Text对象的id属性。
当一个对象类型被实例化时,这个对象的文档作用域会被挂接到使用它的对象的文档作用域上,从而形成了一个作用层级。因此,这个被实例化的对象可以访问它的祖先作用域中的属性及id。这也是所谓的QML动态作用域。通过以下例子来进一步解释:
// TitlePage.qml
import QtQuick 2.0
Item {
property string title
TitleText {
size: 22
anchors.top: parent.top
}
TitleText {
size: 18
anchors.bottom: parent.bottom
}
}
// TitleText.qml
import QtQuick 2.0
Text {
property int size
text: "<b>" + title + "</b>"
font.pixelSize: size
}
在以上示例中,TitleText.qml文件包含了一个QML文档,这个文档定义了TitleText对象类型,同时也定义了一个作用域。在TitlePage.qml文件也包含了一个QML文档,这个文档也定义了一个作用域。在这个文档中使用了TitleText对象类型创建了两个子对象。因此,在QML运行时,TitleText作用域会挂接到TitlePage作用域上,形成一个作用域层级,在TitleText文档中使用了title属性,QML引擎在当前作用域中没有找到这个属性,它会继续在上层作用域中继续查找。因为TitlePage作用域中包含title属性,所以,会将这个引用解析为对TitlePage的title属性。
以下是一个包含内联组件的例子:
Item {
property color defaultColor: "blue"
ListView {
delegate: Component {
Rectangle {
color: defaultColor
}
}
}
}
在这个例子中,Component类型包含了一个QML文档,这个QML文档定义了一个新的对象类型。ListView中创建了一个这个类型的对象,并将它赋值给了delegate属性。这个内联QML文档的作用域被挂接到外层文档的作用域上。因此在Component包含的QML文档中可以使用defaultColor属性。
二、javaScript作用域
在QML程序中编写javaScript代码时,可以按照javaScript作用域知识来确定作用域。例如:
QtObject {
property int a: 3
property int b: 9
function addConstant(b) {
var a = 13;
return b + a;
}
}
在以上程序中,addConstant函数内部的b变量为传入参数b,而不是qtObject类型对象的b属性。
QML对原始javaScript作用域进行了扩展,当QML文档中包含import语句时,javaScript代码可以对引入的对象类型,javaScript资源进行访问。例如:
import QtQuick 2.0
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()
}
}
}
在这个程序中,Text类型对象的color属性通过一个javaScript表达式为其赋值。而这个javaScript表达式调用的是被引入的javaScript资源(code.js)中的函数。
当javaScript代码出现在属性绑定中,作用域规则稍有不同。在QML程序中,如果一个对象含有属性绑定,那么这个对象被称作绑定作用域对象。绑定javaScript表达式中可以直接访问绑定作用域对象中的属性,无需在属性前添加前缀。例如:
Item {
anchors.left: parent.left
}
在以上代码中,Item类型的对象是一个绑定作用域对象。绑定表达式中,可以直接访问Item类型对象的parent属性,而无需添加任何前缀。
当需要在绑定表达式中访问附加属性时,需要注意特别注意。例如:
PathView {
delegate: Component {
Rectangle {
id: root
Image {
scale: root.PathView.scale
}
}
}
}
在以上代码中,Image类型的对象是一个绑定作用域对象。绑定表达式中需要访问的是Rectangle
类型对象的附加属性PathView.scale。如果,不加root前缀,那么绑定表达式中访问的将是Image类型对象的PathView.scale,而这个属性是不存在的。