v-for 和 v-if 在 vue.js 中不能一起工作

问题描述 投票:0回答:9

一个表单用于提交文本,两个选项告诉 vue 在哪一列中显示文本。当选中 col2 单选按钮时,提交的文本应显示在第 2 列中。这种情况不会发生,在第 1 列上显示文本。

我有两个单选按钮,应将值“一”或“二”传递给 newInfo.option 在 submnit 上,方法将表单数据推送到数组“info”。

<input type="radio" id="col1" value="one" v-model="newInfo.col">
<input type="radio" id="col2" value="two" v-model="newInfo.col">

此数据已正确推送到数组“info”,我可以迭代它。我知道这是有效的,因为我可以迭代数组,一个控制台,记录其中的所有数据。所有提交的表单数据都在那里。

接下来我在模板中迭代该数组两次。一次用于 info.col==="one",另一次迭代仅应在 info.col==="two" 时显示。我同时使用 v-for 和 v-if,vue.js 文档说可以这样做,

https://v2.vuejs.org/v2/guide/conditional.html#v-if-with-v-for

<div class="row">
            <div class="col-md-6">
                <ol>
                    <li v-for="item in info" v-if="item.col==='one'">
                        text: {{ item.text }}, col: {{ item.col }}
                    </li>
                </ol>
            </div>
            <div class="col-md-6">
                <ol>
                    <li v-for="item in info" v-if="!item.col==='two'">
                        text: {{ item.text }}, col: {{ item.col }}
                    </li>
                </ol>
            </div>
        </div>

完整的 vue.js 代码位于 github 这里

它正在 gh-pages 上运行here

vue.js radio-button v-for
9个回答
88
投票

为什么不使用计算属性的力量?

computed: {
  infoOne: function () {
    return this.info.filter(i => i.col === 'one')
  },
  infoTwo: function () {
    return this.info.filter(i => i.col === 'two')
  }
}

然后在每个列表上只需迭代其各自的属性而无需检查。示例

<ol>
   <li v-for="item in infoOne">{{item}}</li>
</ol>

这里是工作小提琴


40
投票

来自 Vue 文档

当它们存在于同一节点时,v-if 的优先级高于 v-for。这意味着 v-if 条件将无法访问变量 从 v-for 的范围来看:


<!--
This will throw an error because property "todo"
is not defined on instance.
-->
<li v-for="todo in todos" v-if="!todo.isComplete">
  {{ todo.name }}
</li>

这可以通过将 v-for 移动到包装标签(其中 也更明确):

<template v-for="todo in todos">   
  <li v-if="!todo.isComplete">
     {{ todo.name }}   
  </li> 
</template> 

如果您不介意元素在 html 中保留为“display:none”您可以将 v-show 与 v-for 结合使用


9
投票

您还可以在模板中使用 JavaScript 来过滤 v-for 的数组元素。您可以将信息数组缩小到

v-for="item in infos"
,而不是
v-for="item in infos.filter(info => info.col === 'one')"

由于在回调中使用了 info,因此我将您的信息数组重命名为 infos 以提高我的建议的可读性。

<div class="row">
    <div class="col-md-6">
        <ol>
            <li v-for="item in infos.filter(info => info.col === 'one')">
                text: {{ item.text }}, col: {{ item.col }}
            </li>
        </ol>
    </div>
    <div class="col-md-6">
        <ol>
            <li v-for="item in infos.filter(({ col }) => col === 'two')">
                text: {{ item.text }}, col: {{ item.col }}
            </li>
        </ol>
    </div>
</div>


7
投票
<div class="row">
    <div class="col-md-6">
        <ol>
            <li v-for="item in info">
                <template v-if="item.col==='one'">
                    text: {{ item.text }}, col: {{ item.col }}
                <template>
            </li>
        </ol>
    </div>
    <div class="col-md-6">
        <ol>
            <li v-for="item in info">
                <template v-if="!item.col==='two'">
                    text: {{ item.text }}, col: {{ item.col }}
                <template>
            </li>
        </ol>
    </div>
</div>

5
投票

如果

!
,则从第二个中删除 
v-if="item.col==='two'"

你可以这样做更好(仅迭代一次):

<div class="row" v-for="item in info">
            <div class="col-md-6">
                <ol>
                    <li v-if="item.col==='one'">
                        text: {{ item.text }}, col: {{ item.col }}
                    </li>
                </ol>
            </div>
            <div class="col-md-6">
                <ol>
                    <li v-if="item.col==='two'">
                        text: {{ item.text }}, col: {{ item.col }}
                    </li>
                </ol>
            </div>
        </div>

5
投票

如果由于某种原因无法过滤列表,您可以将同时具有

v-for
v-if
的元素转换为组件,并将
v-if
移动到该组件中。

原始示例

原始循环

<li v-for="item in info" v-if="item.col==='one'">
  text: {{ item.text }}, col: {{ item.col }}
</li>

建议重构

重构循环

<custom-li v-for="item in info" :visible="item.col==='one'">
  text: {{ item.text }}, col: {{ item.col }}
</custom-li>

新组件

Vue.component('custom-li', {
  props: ['visible'],
  template: '<li v-if="visible"><slot/></li>'
})

3
投票

已计算

在大多数情况下,

computed
属性确实是最好的方法,就像DobleL所说的那样,但在我自己的情况下,我在另一个
v-for
中有一个
v-for
,所以计算出来的没有意义对于第二个 v-for。

V秀

因此,与其使用优先级高于

v-if
v-for
(如Mithsew所述),另一种选择是使用没有更高优先级的
v-show
。 它基本上具有相同的功能,并且适用于您的情况。

无包装

使用

v-show
可以避免添加无用的包装元素,就像我在一些答案中看到的那样,在我的例子中,这是避免弄乱 CSS 选择器和 html 结构的要求。

v-show 的缺点

使用

v-show
的唯一缺点是该元素仍会添加到 HTML 中,例如,在我自己的情况下,这仍然会弄乱 CSS :first 选择器。所以我个人实际上选择了
inTheFlow
提到的 .filter() 解决方案。但在大多数基本情况下,你绝对可以使用
v-show
来解决这个问题。

<div class="row">
  <div class="col-md-6">
      <ol>
          <li v-for="item in info" v-show="item.col==='one'">
              text: {{ item.text }}, col: {{ item.col }}
          </li>
      </ol>
  </div>
  <div class="col-md-6">
      <ol>
          <li v-for="item in info" v-show="item.col!=='two'">
              text: {{ item.text }}, col: {{ item.col }}
          </li>
      </ol>
  </div>
</div>

如果您好奇为什么我要在另一个

v-for
中使用
v-for
,这里是我的用例的精简版本:

它是一个对话列表(这是一个计算属性),然后显示每个对话中所有参与者的头像,但当前正在查看它的用户的头像除外。

<a v-for="convo in filteredConversations" class="card">
  <div class="card-body">
      <div class="row">
          <div class="col-auto">
            <div class="avatar-group">
                <div class="avatar" v-for="participant in convo.participants.filter(info => !thatsMe(info))">
                    <img :src="userAvatarUrl(participant)" :alt="participant.name" class="avatar-img">
                </div>
            </div>
          </div> ...

2
投票

您的第二个检查是

!item.col==='two'
,并且只有在 not 等于“二”时才会显示。

编辑:! not 运算符可能比 === 绑定更紧密,因此总是返回 false。添加括号来控制应用顺序。我说可能是因为这可能是我不熟悉的 Vue 魔法,而不是纯粹的 JavaScript 表达式。

我想你想删除那个感叹号。或者使其

!(item.col==='one')
显示“one”以外的任何值。


0
投票

对我来说,最好的选择是使用过滤器。

<div v-for="target in targets.filter((target) => target.zone_id == zone.id)">
  {{ target.id}}
</div>
© www.soinside.com 2019 - 2024. All rights reserved.