You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

QML中ListModel更新时间戳不触发add Transition的实现方法问询

核心问题根因

你当前触发不必要add动画的核心原因是onNumNotificationsChanged回调里执行了全量clear() + 重新insert()操作,等于每次更新数据都把整个列表重建,自然所有条目都会触发add过渡。你可以选择以下任意方案解决时间更新的需求,同时避免多余动画:


方案1:存储绝对时间戳,委托内动态计算相对时间(最推荐)

该方案完全不需要频繁更新模型,从根源避免触发动画:

  • 模型中不再存储动态变化的相对分钟数,改为存储通知发布时的绝对Unix时间戳,该值固定,通知创建后不会变更
  • 在列表委托中新增定时器,每分钟用当前时间减去绝对时间戳计算最新相对时长,直接更新文本即可

示例代码:

property int numNotifications: backend_service.num_notifications

onNumNotificationsChanged: {
    // 改为增量插入,只加新增通知,不要全量清空
    for(var x=0; x<numNotifications; x++) {
        var notif = backend_service.notifications.get(x);
        // 用通知唯一标识判断是否已存在,避免重复插入
        var isExist = false
        for(var i=0; i<notificationModel.count; i++) {
            if(notificationModel.get(i).notifId === notif.id) {
                isExist = true
                break
            }
        }
        if(!isExist) {
            // 插入时存固定的绝对时间戳,不要存动态的相对时间
            notificationModel.insert(0, {
                "notifId": notif.id,
                "name":notif.name,
                "createTimestamp": notif.createTimestamp
            })
        }
    }
}

Rectangle {
    height: 500
    width: 0.90 * parent.width
    anchors {
        top: parent
        topMargin: 30
        left: parent.left
        leftMargin: 45
    }
    ListView {
        anchors.fill: parent
        model: notificationModel
        delegate: notificationDelegate
        spacing: 30

        add: Transition {
            NumberAnimation { property: "opacity"; from: 0; to: 1; duration: 1000 }
        }
    }
}

ListModel {
    id: notificationModel
}

Component {
    id: notificationDelegate
    Row {
        spacing: 20
        Text { text: name; color: "white" }
        Text {
            color: "white"
            // 动态计算相对分钟数
            text: Math.floor((Date.now()/1000 - createTimestamp) / 60) + "分钟"
            Timer {
                interval: 60000 // 每分钟刷新一次
                running: true
                repeat: true
                onTriggered: parent.text = Math.floor((Date.now()/1000 - createTimestamp) / 60) + "分钟"
            }
        }
    }
}

方案2:调用ListModel的set()方法更新指定字段

如果你确实需要把相对时间存在模型里,直接调用ListModel.set(index, propertyObject)方法更新指定条目指定字段即可,该方法只会触发dataChanged信号,不会触发条目新增的add过渡动画:

// 每分钟执行一次的时间更新逻辑
function updateAllNotificationTime() {
    for(var i=0; i<notificationModel.count; i++) {
        var curNotif = notificationModel.get(i)
        // 从后端拿到对应通知的最新时间
        var latestTime = backend_service.getNotifLatestTime(curNotif.notifId)
        // 仅更新time字段,不会触发add动画
        notificationModel.set(i, {"time": latestTime})
    }
}

注意不要调用remove+insert或者clear+全量插入的逻辑,只有纯set操作不会触发add动画。


方案3:直接绑定后端通知对象的属性

如果后端返回的notif对象的time字段是Qt元属性(带有notify信号),可以直接把该对象存在模型中,委托内直接绑定属性即可自动更新,无需手动修改模型:

// 插入时存储原始通知对象
notificationModel.insert(0, {"name":notif.name, "rawNotif": notif})

// 委托内直接绑定后端属性
Text { text: rawNotif.time; color: "white" }

只要后端更新time字段时触发了对应notify信号,前端文本会自动刷新,完全不需要操作模型。


内容的提问来源于stack exchange,提问作者Evan Krause

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.03 15:45:00