QML概念及框架--继承JavaScript

    QML推荐使用属性绑定和现有的QML元素来创建界面。为了允许执行更高级的行为,QML紧密集成了必要的JavaScript代码。QML中提供的JavaScript环境比在网页浏览器中的更严格。在QML中不可以添加或者修改JavaScript全局对象的成员,因为这样做可能会使一个没有经过声明的变量。在QML中会抛出一个异常,所以所有的局部变量都应该明确的声明。除了标准的JavaScript属性,在QML全局对象中还包含了一些很有用的函数,可以用来简化创建界面以及和QML环境进行交互。

1. 内联JavaScript

    较小的JavaScript函数可以和其他QML声明一起写在QML组件中。这些内联函数会像一般的函数一样添加到QML元素中:

import QtQuick 2.4

Item {
    function factorial(a) {
        a = parseInt(a)
        if(a <= 0)
            return 1;
        else
            return a * factorial(a-1)
    }
    MouseArea {
        anchors.fill: parent
        onClicked: console.log(factorial(10))
    }
}
    像一般函数一样,在一个QML组件根元素中的内联函数可以在组件外被调用。如果不想被被外部调用,那么这个函数可以添加到一个根元素以外的其他元素中,或者编写进一个外部的JavaScript文件中。

2. 分离的JavaScript文件

   大块的JavaScript代码需要写在一个独立的文件中,这些文件可以通过使用import语句导入QML文件中,就像导入QML模块一样。

前面代码中国的factorial()函数可以移动到一个外部名为“factorial.js”的文件中,然后进行访问:

import QtQuick 2.4
import "factorial.js" as MathFunctions

Item {
    MouseArea {
        anchors.fill: parent
        onClicked: console.log(MathFunctions.factorial(10))
    }
}

    相对和绝对的JavaScript路径都可以被导入。如果脚本文件不可访问,那么将发生错误。如果JavaScript需要从赢网络资源中获取,那么组件的状态会被设置为Loading,直到脚本被下载完毕。被导入的JavaScript文件总是使用as关键在来进行限定,每一个JavaScript文件的限定符必须是唯一的,在限定符合JavaScript文件之间是一对一映射的。

3. 代码隐藏(Code-Behind)实施文件

    大多数的JavaScript文件被导入一个QML是有状态的,它们经常作为该QML文件的逻辑实现。在这种情况下,为了使QML组件的实例有正确的行为,每个实例都需要JavaScript对象和状态的一个独立备份。导入一个JavaScript文件时的默认行为死为每一个QML组件实例提供一个唯一的、独立的备份。JavaScript代码和QML组件实例运行在相同的范围,因此可以访问和操作对象和声明的属性。

   一个QML中对JS文件中的值作了修改,再次调用时,这个值发生了变化。。。。。。

4. 无状态的JavaScript库

   一些JavaScript文件的行为更像库文件,它们提供了一组无状态的辅助函数来提供输入和计算输出,但是从来不直接操作QML组件实例。如果每一个QML组件实例都有一个这些库的拷贝,那么就会造成浪费。JavaScript程序员可以使用一个pragma来致命一个特定的文件是一个没有状态的库。

.pragma library

function factorial(a) {
    a = parseInt(a)
    if(a <= 0) {
        return 1;
    } else {
        return a * factorial(a -1)
    }
}
    这个prama声明必须出现在除了注释以外的所有JavaScript代码以前。虽然QML值可以作为函数的参数进行传递。不过这些共享的、无状态的库文件不能直接访问QML组件实例对象或属性。

5. 从其他JavaScript文件进行导入

    如果一个JavaScript文件需要使用定义在其他JavaScript文件中的函数,可以通过使用Qt.include()函数来导入其他的文件。这样会将其他文件中的所有函数导入到当前文件的命名空间中。例子:

import QtQuick 2.4
import "script.js" as MyScript

Item {
    width: 100; height: 100

    MouseArea {
        anchors.fill: parent
        onClicked: {
            MyScript.showCalculations(10)
            console.log("Call factorial() from QML: ", MyScript.factorial(10))
        }
    }
}
script.js文件的内容:

Qt.include("factorial.js")

function showCalculations(value) {
    console.log("Call factorial() from script.js: ", factorial(value))
}
factorial.js文件的内容:

function factorial(a) {
    a = parseInt(a)
    if(a <= 0) {
        return 1;
    } else {
        return a * factorial(a -1)
    }
}
    注意,调用Qt.include()将会从factorial.js导入所有的函数到MyScript命名空间,这就意味着QML组件可以直接使用MyScript.factorial()来访问factorial()函数。

6. 在启动时运行JavaScript

    有时需要在应用程序(或者组件实例)启动时运行一些命令代码,但如果仅仅包含启动脚本作为全局代码,因为QML环境还没有完全建立起来,所以这样会有严重的局限,例如一些对象可能还没有被创建或者一些属性绑定还没有被运行。后面讲述的QML JavaScript限制一段中涵盖了全局脚本代码的确切限制。QMLComponent元素提供了一个附加的onCompleted属性可以用来在QML环境完全建立后切换到启动脚本代码的执行。

Rectangle {
    function startFunction(){
        //...startup code
    }
    
    Component.onCompleted: startupFunction();
}
    任何在QML文件中的元素,包含嵌套的元素和嵌套的QML组件实例,都可以使用这个附加属性。如果有多个onCompleted()处理器在启动时执行,它们会以未定义的顺序依次执行。类似的,Component::onDestruction附加属性会在组件销毁时触发。

7. 属性赋值与属性绑定

   当同时使用QML和JavaScript时,区分QML属性绑定和JavaScript赋值是很重要的。在QML中,使用“属性:值”语法来创建一个属性绑定。

Rectangle {
    width: otherItem.width //属性绑定,Rectangle的值会随otherItem.width的更改而更新
    
    Component.onCompleted: {
        width: otherItem.width  //属性赋值,不会调用QML的属性绑定
    }
}
8. 在JavaScript中接收QML信号

    要接收一个QML信号,可以使用信号的connect()函数将它关联到一个JavaScript函数上。

Item {
    id: item
    width: 200; height: 200
    
    MouseArea {
        id: mouseArea
        anchors.fill: parent
    }
    
    Component.onCompleted: {
        mouseArea.clicked.connect(MyScript.jsFunction)  //MouseArea的信号关联到script.js中的jsFunction()上
    }
}
9. QML JavaScript限制

    QML执行标准的JavaScript代码,会有下面的限制:

    (1) JavaScript代码不能修改全局对象

     在QML中,全局对象是一个常量,现有的属性不能够被修改和删除,也不能够创建新的属性。大多数的JavaScript程序并不是有意修改全局对象的,然而,JavaScript自动生成一个为声明的变量是全局对象的隐式修改,在QML中是非法的:

//a在作用链中不存在
//非法修改未声明的变量
a = 1;
for(var ii = 1; i < 10; ++ii)
    a = a * ii
console.log("Result: " + a)
    它可以简单修改为合法的代码:

a = 1;
for(var ii = 1; i < 10; ++ii)
    a = a * ii
console.log("Result: " + a);
    无论隐式的或者显式的对全局对象的修改都会导致一个异常

    (2) 全局代码运行在一个缩小的范围

    在启动时,如果QML文件包含一个外部的JavaScript文件和“全局”代码,它会只包含该外部文件和这个全局对象的范围内执行。也就是说,它不会像通常那样访问QML对象和属性。全局代码只访问脚本中的局部变量是允许的。

//有效的全局代码
var colors = ["red", "blue", "green", "orange", "purple"]
    非法的全局代码--“rootObject”变量未定义

var initialPosition = {rootObject.x, rootObject.y}
    存在此限制是因为QML环境尚未被完全建立。要宰环境完全启动后运行后运动代码。

    (3) 目前在QML中this值是未定义的,要引用任何元素,可以使用其id。

Item {
    width: 200; height: 200

    function mouseAreaClicked(area) {
        console.log("Clicked in area at: " + area.x + "," + area.y)
    }
    //因为this未定义,所以下面的代码不会工作
    MouseArea{
        height: 50; width: 200
        onClicked: mouseAreaClicked(this)
    }
    //这样可以将area2传递给函数
    MouseArea {
        id: area2
        y: 50; height: 50; width: 200
        onClicked: mouseAreaClicked(area2)
    }
}

  • 2
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值