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)

    }

}

 

from:  https://blog.csdn.net/u012419303/article/details/45896263

 

posted @ 2023-02-07 10:20  imxiangzi  阅读(479)  评论(0编辑  收藏  举报