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

Vue+SignalR场景下异步获取新数据时v-for绑定列表未更新问题咨询

问题原因&解决方案

核心问题:SignalR回调的this指向错误

你当前的UpdateAccount事件回调使用了普通函数声明,函数内部的this指向的是SignalR连接实例,根本不是Vue实例,所以你写的this.account = accountData并没有修改到Vue内部的响应式数据,自然不会触发页面重新渲染。你打印出来的是外部作用域的accountData变量,和Vue的响应式数据没有绑定关联。

修复方案

方案1(推荐):把SignalR逻辑移入Vue实例内部

将SignalR的初始化、事件监听都放到Vue的mounted生命周期钩子中,回调使用箭头函数保证this指向Vue实例,修改后的JS代码如下:

<script type="module" async>
    import { server } from "./assets/js/config.js";
    import { getProject } from "./assets/js/saleproject.js";
    import { getAccountById } from "./assets/js/account.js";
    import { createApp } from 'https://unpkg.com/vue@3.2.4/dist/vue.esm-browser.js'
    // 从querystring获取accountId
    let accountId = getQueryStringByParameter("accountId");

    // 调用API加载初始数据
    var accountData = await getAccountById(accountId);

    // 项目相关逻辑
    let projectData = null
    if (accountData.lastOrder.saleProjectCode != null) {
        projectData = await getProject(accountData.lastOrder.saleProjectCode)
        console.log('Sale Project')
        console.table(accountData.lastOrder)
    }

    // 计算总金额
    let totalDue = projectData ? (accountData.lastOrder.amount - accountData.lastOrder.amountFilled) * projectData.salePrice : 0;

    function getQueryStringByParameter(name) {
        name = name.replace(/[\[]/, "\\[").replace(/[\]]/, "\\]");
        var regex = new RegExp("[\?&]" + name + "=([^&#]*)"),
            results = regex.exec(location.search);
        return results == null
            ? ""
            : decodeURIComponent(results[1].replace(/\+/g, " "));
    }

    // Vue实例创建
    createApp({
        data: () => ({
            account: accountData,
            walletValid: accountData.account.isValidWithdrawAddress,
            depositAddress: server + "/qr/" + accountData.account.depositAddress,
            clipboardDepositAddress: accountData.account.depositAddress,
            salePrice: totalDue,
            connection: null // 将SignalR连接存到Vue实例上方便后续管理
        }),
        methods: {
            copyDepositAddress() {
                navigator.clipboard.writeText(this.clipboardDepositAddress)
            }
        },
        async mounted() {
            // 初始化SignalR连接
            this.connection = new signalR.HubConnectionBuilder()
                .withUrl(server + "/statusHub")
                .withAutomaticReconnect()
                .build();

            await this.connection.start()
            try {
                await this.connection.invoke("AddToGroup", accountId)
            } catch (err) {
                console.error(err.toString())
            }

            // 回调使用箭头函数,this自动指向Vue实例
            this.connection.on("UpdateAccount", async (currentAccountId, reason) => {
                const newAccountData = await getAccountById(accountId);
                // 直接修改Vue的响应式数据自动触发渲染
                this.account = newAccountData;
                console.log("Update from signalr: " + reason + ' ' + currentAccountId);
            })

            this.connection.onclose(async () => {
                await this.connection.start();
            });
        }
    }).mount("#js-account");
</script> 

方案2(快速修复无需移动代码):把Vue实例存为变量直接修改

如果你不想改动现有SignalR的代码位置,可以把创建好的Vue实例存到一个变量中,在回调中直接修改这个变量上的account属性即可:

// 先存储创建好的Vue实例
const vueApp = createApp({
    // 原有Vue配置保持不变
}).mount("#js-account");

// 原有SignalR回调修改为如下内容
connection.on(
    "UpdateAccount",
    async function (currentAccountId, reason) {
        accountData = await getAccountById(accountId);
        // 直接修改Vue实例的响应式数据
        vueApp.account = accountData;
    }
);

额外校验

你当前v-for使用deposit.id作为key是符合要求的,不会因为key的问题导致列表不更新,修改完指向问题后即可正常触发渲染。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.30 01:24:03