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

mnemlml8  于 2022-11-17  发布在  Vue.js
关注(0)|答案(8)|浏览(200)

一个表单用于提交文本,两个选项用于告诉vue在哪一列显示文本。选中第2列单选按钮时,提交的文本应显示在第2列中。但实际上没有发生这种情况,文本显示在第1列中。
我有两个单选按钮,它们应该将值'one'或'two'传递给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'中,我可以迭代它。我知道这是有效的,因为我可以迭代数组,一个console.log记录其中的所有数据。所有提交的表单数据都在那里。
接下来,我在模板中迭代这个数组两次。一次是为了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 here
它在这里的gh页面上运行

des4xlb0

des4xlb01#

为什么不使用计算属性的强大功能?

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>

这里的工作fiddle

pkwftd7m

pkwftd7m2#

来自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移动到 Package 标签(也更明确)来修复此问题:*
<template v-for="todo in todos">   
  <li v-if="!todo.isComplete">
     {{ todo.name }}   
  </li> 
</template>

如果你不介意你的视图继续在html中使用“display:none”,你可以将v-show和v-for一起使用,没有任何问题。

eiee3dmh

eiee3dmh3#

<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>
gmxoilav

gmxoilav4#

如果由于某种原因,无法筛选清单,您可以将同时具有v-forv-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>'
})
avwztpqn

avwztpqn5#

您也可以在模板中使用JavaScript来过滤v-for的数组元素。您可以将info-array的范围缩小到v-for="item in infos.filter(info => info.col === 'one')",而不是v-for="item in infos"
我将你的info-array重命名为infos,以提高我的建议的可读性,因为在回调中使用了info。

<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(info => info.col === 'two')">
                text: {{ item.text }}, col: {{ item.col }}
            </li>
        </ol>
    </div>
</div>
olqngx59

olqngx596#

如果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>
0yg35tkg

0yg35tkg7#

您的第二个检查是!item.col==='two',仅当它等于'two'时才会显示。
编辑:!not操作符可能比===绑定得更紧密,所以它总是返回false。添加括号来控制应用程序的顺序。我说可能是因为它可能是一个我不熟悉的Vue魔术,而不是一个纯粹的JavaScript表达式。
我想你应该去掉那个感叹号,或者把它改成!(item.col==='one'),以便显示除'one'以外的任何值。

gev0vcfq

gev0vcfq8#

已计算

在大多数情况下,computed属性确实是最好的方法,就像DobleL说的那样,但是在我自己的例子中,我在另一个v-for中有一个v-for,所以计算出的对于第二个v-for没有意义。
"V秀"
因此,与其使用优先级高于v-forv-if(如Mithsew所述),还不如使用优先级没有那么高的v-show

**无 Package **

使用v-show可以避免添加无用的 Package 器元素,正如我在一些答案中看到的那样,在我的例子中,这是避免弄乱CSS选择器和html结构的要求。
"V型秀的缺点"
使用v-show的唯一缺点是元素仍然会被添加到HTML中,这在我自己的例子中仍然会弄乱CSS:例如第一个选择器。所以我个人实际上选择了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> ...

相关问题