QML 编码约定

本文档包含我们在文档和示例中遵循并建议他人遵循的 QML 编码约定。

QML 对象声明

在我们的文档和示例中,QML 对象属性总是按以下顺序排列:

  • id
  • 属性声明
  • 信号声明
  • JavaScript 函数
  • 对象属性
  • 子对象

为了提高可读性,我们用空行来分隔这些不同的部分。

例如,一个假想的照片QML 对象看起来是这样的:

Rectangle {
    id: photo                                               // id on the first line makes it easy to find an object

    property bool thumbnail: false                          // property declarations
    property alias image: photoImage.source

    signal clicked                                          // signal declarations

    function doSomething(x)                                 // javascript functions
    {
        return x + photoImage.width;
    }

    color: "gray"                                           // object properties
    x: 20                                                   // try to group related properties together
    y: 20
    height: 150
    width: {                                                // large bindings
        if (photoImage.width > 200) {
            photoImage.width;
        } else {
            200;
        }
    }

    states: [
        State {
            name: "selected"
            PropertyChanges { target: border; color: "red" }
        }
    ]

    transitions: [
        Transition {
            from: ""
            to: "selected"
            ColorAnimation { target: border; duration: 200 }
        }
    ]

    Rectangle {                                             // child objects
        id: border
        anchors.centerIn: parent
        color: "white"

        Image {
            id: photoImage
            anchors.centerIn: parent
        }
    }
}

分组属性

如果使用一组属性中的多个属性,可以考虑使用组符号代替点符号,这样可以提高可读性。

例如

Rectangle {
    anchors.left: parent.left; anchors.top: parent.top; anchors.right: parent.right; anchors.leftMargin: 20
}

Text {
    text: "hello"
    font.bold: true; font.italic: true; font.pixelSize: 20; font.capitalization: Font.AllUppercase
}

可以这样写:

Rectangle {
    anchors { left: parent.left; top: parent.top; right: parent.right; leftMargin: 20 }
}

Text {
    text: "hello"
    font { bold: true; italic: true; pixelSize: 20; capitalization: Font.AllUppercase }
}

非限定访问

为了提高可读性和性能,请务必明确引用父组件的 id 属性:

Item {
    id: root

    property int rectangleWidth: 50

    Rectangle {
        width: root.rectangleWidth
    }
}

必填属性

当需要组件外部定义的数据时,可使用必填属性来明确说明。必须设置必填属性,否则创建组件将失败。这比无条件查找更可取,因为它们的性能更高,并允许用户和工具对外部属性的类型进行推理。此外,它们还消除了组件对创建环境的假设。

信号处理器

在信号处理器中处理参数时,应使用明确命名参数的函数:

MouseArea {
    onClicked: event => { console.log(`${event.x},${event.y}`); }
}

JavaScript 代码

为了提高可读性和可维护性,我们通常在单独一行中声明每个属性,即使是简单的表达式也是如此。

Rectangle {
    color: "blue"
    width: parent.width / 3
}

对于跨多行的脚本表达式,我们使用块格式:

Rectangle {
    color: "blue"
    width: {
        var w = parent.width / 3;
        console.debug(w);
        return w;
    }
}

如果脚本超过几行,或者可以被不同的对象使用,我们建议创建一个函数并像这样调用它:

function calculateWidth(object : Item) : double
{
    var w = object.width / 3;
    // ...
    // more javascript code
    // ...
    console.debug(w);
    return w;
}

Rectangle {
    color: "blue"
    width: calculateWidth(parent)
}

另外要注意的是,建议为函数添加类型注解,以便更轻松地推理和重构应用程序,因为参数和返回类型都可以从函数签名中直接看到。

对于较长的脚本,我们会将函数放在自己的 JavaScript 文件中,然后像这样导入:

import "myscript.js" as Script

Rectangle { color: "blue"; width: Script.calculateWidth(parent) }

如果代码长度超过一行,因此在一个代码块中,我们会使用分号来表示每条语句的结束:

MouseArea {
    anchors.fill: parent
    onClicked: event => {
        var scenePos = mapToItem(null, event.x, event.y);
        console.log("MouseArea was clicked at scene pos " + scenePos);
    }
}

© 2025 The Qt Company Ltd. Documentation contributions included herein are the copyrights of their respective owners. The documentation provided herein is licensed under the terms of the GNU Free Documentation License version 1.3 as published by the Free Software Foundation. Qt and respective logos are trademarks of The Qt Company Ltd. in Finland and/or other countries worldwide. All other trademarks are property of their respective owners.