【问题标题】:Vue.js not correctly rendering dynamically loaded select tag optionsVue.js 未正确呈现动态加载的选择标签选项
【发布时间】:2017-04-24 17:17:31
【问题描述】:

我正在尝试使用从 Vue 对象加载的选项来渲染一个选择标签,但是,正如您所看到的那样,它看起来有些问题:

现在这是选择标签的标记:

<div class="form-group ui-model">
    @Html.LabelFor(m => m.SenderWalletId, new { @class = "control-label col-sm-2" })
    <div class="col-sm-10">
        <select class="form-control" v-model="selectedSenderWallet">
            <option v-if="!walletsLoaded" disabled>Loading wallets...</option>
            <option v-if="walletsLoaded" v-for="wallet in wallets" v-bind:value="wallet.id">{{ wallet.description }}</option>
        </select>
        @Html.HiddenFor(m => m.SenderWalletId, new { }, new { value = "selectedSenderWallet" })
        @Html.ValidationMessageFor(m => m.SenderWalletId)
    </div>
</div>

这是用于创建 Vue 应用程序的脚本,以及用于处理钱包的 SignalR(从我的存储库成功加载钱包后,集线器会调用 setWallets):

<script>
    var walletLinkText = Vue.extend({
        props: ['wallet'],
        template: '<span>{{ linkText }}</span>',
        computed: {
            linkText: function () {
                return this.wallet.description + ' (' + this.wallet.currentAmountFormatted + ')';
            }
        }
    });

    var uiModel = new Vue({
        el: '.ui-model',
        data: {
            wallets: [],
            walletsLoaded: false
        },
        components: {
            'wallet-link-text': walletLinkText
        }
    });

    $(function() {
        var walletsHubProxy = $.connection.walletsHub;

        walletsHubProxy.client.updateWallet = function (...) {
            ...
        };

        walletsHubProxy.client.setWallets = function (currentWallets) {
            uiModel.wallets = currentWallets;
            uiModel.walletsLoaded = true;
        };

        $.connection.hub.start().done(function() {
            walletsHubProxy.server.getWallets();
        });
    });
</script>

问题是我确定钱包已正确加载,正如您在菜单中看到的那样:

这是上面的 html 标记:

<ul class="nav navbar-nav ui-model">
    <li class="dropdown">
        <a href="#" class="dropdown-toggle" data-toggle="dropdown" role="button" aria-haspopup="true" aria-expanded="false">Wallets <span class="caret"></span></a>
        <ul class="dropdown-menu">
            <li v-if="!walletsLoaded"><a><i class="fa fa-spinner fa-pulse"></i> Loading...</a></li>
            <li v-if="walletsLoaded && !wallets.length"><a>No wallets.</a></li>
            <li v-if="walletsLoaded" v-for="wallet in wallets">
                <a v-bind:href="'@Url.Content(string.Format("~/Wallets/"))' + wallet.id">
                    <wallet-link-text :wallet="wallet"></wallet-link-text>
                </a>
            </li>
            <li role="separator" class="divider"></li>
            <li><a href="@Url.Action("Add", "Wallets")"><i class="fa fa-fw fa-edit"></i> Add new</a></li>
        </ul>
    </li>
</ul>

那么我哪里错了?我觉得我被一些非常简单的事情困住了。

【问题讨论】:

  • 我不明白问题出在哪里。最后的屏幕截图似乎表明一切正常。那么第一个屏幕截图的情况何时/如何发生?通常,当出现错误并且模板不是由 Vue 编译时,Vue 应用程序看起来像这样。看看你的控制台。
  • 问题出在第一个屏幕截图中:根本没有呈现选项。我发布了其他屏幕截图来支持这样一个事实,即使用相同的 Vue 应用程序正确呈现菜单而不是选择标签。并且控制台没有显示任何内容(是的,我使用的是开发版)。
  • 尝试在第二个选项中使用v-else而不是v-if="walletsLoaded"
  • 我已经尝试移除条件渲染,甚至尝试了v-else,但结果还是一样。问题肯定不在条件渲染上。

标签: javascript jquery asp.net-mvc mvvm vue.js


【解决方案1】:

显然 Vue 只能安装在一个上下文元素中: .ui-model 指的是 DOM 中的多个元素,因此只有第一个被正确呈现(菜单)。如果我创建另一个 Vue 应用程序,代码将按预期工作:

<div class="form-group" id="wallets-app">
    @Html.LabelFor(m => m.WalletId, new { @class = "control-label col-sm-2" })
    <div class="col-sm-10">
        <select class="form-control" v-model="selectedWallet">
            <option v-if="!walletsLoaded" disabled>Loading wallets...</option>
            <option v-else v-for="wallet in wallets" v-bind:value="wallet.id">{{ wallet.description }}</option>
        </select>
        @Html.HiddenFor(m => m.WalletId, new { }, new { value = "selectedWallet" })
        @Html.ValidationMessageFor(m => m.WalletId)
    </div>
</div>

<script>
    var app = new Vue({
        el: '#wallets-app',
        data: {
            wallets: [],
            walletsLoaded: false,
            selectedWallet: ''
        }
    });

    //SignalR code to sync hubs and ui
</script>

我希望在多个元素之间共享单个数据数组,以便每个元素都有自己的 html 表示形式,即视图。相反,我必须将钱包数组传递给我希望对更新做出反应的每个 Vue 应用程序。

嗯,这对我来说似乎效率低下,但我确定我错过了一些东西。随意添加任何建议和/或更正。

编辑: 实现我想要的结果的正确方法是将所有数据简单地放入一个 store 对象中,以便在多个组件之间共享相同的数据(例如每个钱包的菜单项)。

<div class="form-group" id="select-wallet">
    @Html.LabelFor(m => m.WalletId, new { @class = "control-label col-sm-2" })
    <div class="col-sm-10">
        <select class="form-control" v-model="selectedWallet">
            <option v-if="!sharedData.walletsLoaded" disabled>Loading wallets...</option>
            <option is="wallet-select-option" v-else v-for="wallet in sharedData.wallets" v-bind:wallet="wallet"></option>
        </select>
        @Html.HiddenFor(m => m.WalletId, new { }, new { value = "selectedWallet" })
        @Html.ValidationMessageFor(m => m.WalletId)
    </div>
</div>

<script>
    var store = {
        data: {
            wallets: [],
            walletsLoaded: false
        }
    };

    Vue.component('wallet-select-option', {
        props: ['wallet'],
        template: '<option v-bind:value="wallet.id">{{ wallet.description }}</option>'
    });

    var selectWallet = new Vue({
        el: '#select-wallet',
        data: {
            sharedData: store.data,
            selectedWallet: ''
        }
    });


    $(function () {
        var walletsHubProxy = $.connection.walletsHub;

        walletsHubProxy.client.updateWallet = function (...) {
            ...
        };

        walletsHubProxy.client.setWallets = function (currentWallets) {
            store.data.wallets = currentWallets;
            store.data.walletsLoaded = true;
        };

        $.connection.hub.start().done(function () {
            walletsHubProxy.server.getWallets();
        });
    });
</script>

我忘了提到具有三个参数的 @Html.HiddenFor 是我编写的一个扩展方法,用于帮助我处理 v-bind 属性,这些属性无法被 razor 语法解析。

【讨论】:

    猜你喜欢
    • 2021-07-07
    • 1970-01-01
    • 2019-09-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-03-04
    相关资源
    最近更新 更多