v-if inside v-for - 在两列中显示项目列表
Posted
技术标签:
【中文标题】v-if inside v-for - 在两列中显示项目列表【英文标题】:V-if inside v-for - display list of items in two columns 【发布时间】:2019-04-04 04:16:21 【问题描述】:很抱歉发布此消息,因为我可以看到许多与此类似的问题已被多次询问。以下是几乎可以帮助我的那些 - 以及为什么他们没有:
This 一个是因为计算不应该在渲染中完成,而是在方法/计算部分。这对我没有帮助。 This 一个是使用两个不同的模板,在模板标签上写v-if
。在我的情况下这似乎很愚蠢,因为这两个模板将 98% 相同。
This Medium-article 解决了一个非常接近我的问题非常。但是,-在他的情况下,这是对用户的过滤(通过计算属性解决),而不是在某个迭代中插入 sn-p 代码的 if 子句(我认为我正在寻找) .
问题
我有一个从 API 中提取的项目列表,因此数量会发生变化。我希望它们显示在两列中:
-----------------
| Item1 Item5 |
| Item2 Item6 |
| Item3 Item7 |
| Item4 |
-----------------
我正在使用 v-for
循环遍历它们。
我的尝试
-
使用纯 CSS 和
display: flex
但这只能做到这一点:
-----------------
| Item1 Item2 |
| Item3 Item4 |
| Item5 Item6 |
| Item7 |
-----------------
-
将 CSS 与
column-count: 2;
结合使用
但这打破了列中间元素,display: block; overflow: hidden;
和许多其他尝试。应该说,这些元素的高度是可以变化的。
-
所以我放弃了使用 CSS 修复它。
如果是php
,那么我会简单地做这样的事情:
<?php
if( $index == count( $items)/2 ):
echo '</div>';
echo '</div>';
echo '<div class="col-md-6">';
echo '<div class="item-container">';
endif;
?>
...但事实并非如此。我正在寻找 vue 的替代品。我试过this:
#if key === Number( items.length / 2 )
</div>
</div>
<div class="col-md-6">
<div class="item-container">
/if
但它不起作用。据我所知,这不是“vue 方式”。但我不知道是什么。 :-/
这样的事情存在吗?
我当前代码的简化
<div class="col-md-12">
<div class="items-container">
<div class="item-container" v-for="item, key in items['data']">
<!-- A BUNCH OF ITEM-INFO -->
</div><!-- /.item-container -->
</div><!-- /.items-container -->
</div><!-- /.col-md-12 -->
【问题讨论】:
为了避免重复关闭,请edit your question 引用其他帖子并解释它们如何/为什么不适合您? 我现在添加了最接近解决方案的那些,以及为什么我不能使用它们 (@Phil)。 干杯。我想您不希望为items-container
设置固定高度,对吗?所以您希望第二列从基于项目数的逻辑中间点开始?
认为您可以使用条件类 `v-for="item, key, index in items['data']" v-bind:class=" clearfix: !(索引 % 2) "1
@Phil :是的,-我强烈希望不要设置高度,因为内容将从 API 中提取,所以我无法控制一堆东西被拉。所以网格应该尽可能灵活。
【参考方案1】:
我要做的是创建一个计算属性,将 items 数组划分(或分块)为适当数量的列。
这是一个使用 flexbox 布局和一个额外的 column 元素的示例。
new Vue(
el: 'main',
data:
items: ['Item 1', 'Item 2', 'Item 3', 'Item 4', 'Item 5', 'Item 6', 'Item 7'],
cols: 2
,
computed:
columns ()
let columns = []
let mid = Math.ceil(this.items.length / this.cols)
for (let col = 0; col < this.cols; col++)
columns.push(this.items.slice(col * mid, col * mid + mid))
return columns
)
.container
display: flex;
border: 1px solid;
.col
margin: 10px;
border: 1px solid;
flex-grow: 1;
display: flex;
flex-direction: column;
.item-container
border: 1px solid;
padding: 5px;
margin: 5px;
<script src="https://cdn.jsdelivr.net/npm/vue@2.5.17/dist/vue.min.js"></script>
<main>
<p><label>Columns:<label> <input type="number" v-model="cols"></p>
<div class="container">
<div class="col" v-for="column in columns">
<div class="item-container" v-for="item in column">item</div>
</div>
</div>
</main>
如果您想要一种不太冗长的方式来分块 items 数组,请参阅 Split array into chunks
【讨论】:
【参考方案2】:很高兴看到有人偶然发现与我相同的问题。我必须在每列中放置 6 个项目。我将 API 响应分割成列,然后打印出来。
let allCategory = response.body.Categories.slice(); //clone
while (allCategory.length > 0)
let chunk = allCategory.splice(0,6);
this.ColArray.push(chunk);
ColArray 是一个数组,它将包含列的数组。它看起来像这样:
ColArray: [
Column1: [
Item1,
Item2,
Item3,
],
Column2: [
...
]
]
在 Vue 中它只会被循环,像这样:
<div v-for="(col,colIndex) in ColArray" :key="'cate_col'+colIndex" class="col-md-2">
<div v-for="(row,rowIndex ) in col" :key="'cate_row'+colIndex + rowIndex" class="row">
row
</div>
</div>
这是一个小提琴示例:
https://jsfiddle.net/keysl183/50wL7mdz/775484/
【讨论】:
这是一个非常好的解决方法。但是,在给定的迭代中使用 Vue 不可能打印/回显/检查某些东西,这真的是真的吗?在那种情况下,我必须以某种方法或其他方式来做吗? 您可以在计算中实现拼接和切片,因此您不需要使用方法【参考方案3】:适用于尝试实现相同结果(将项目分成列)但拆分对象而不是数组的任何人。
此解决方案基于 Phil 选择的答案。
它使用 Object.keys 循环遍历对象并使用 Object.entries 从对象中返回一个数组。无需通过 html 模板中的索引进行访问,而是通过键来访问。
new Vue(
el: 'main',
data:
items:
item1: name: 'Item 1' ,
item2: name: 'Item 2' ,
item3: name: 'Item 3' ,
item4: name: 'Item 4' ,
item5: name: 'Item 5' ,
item6: name: 'Item 6' ,
item7: name: 'Item 7' ,
item8: name: 'Item 8' ,
item9: name: 'Item 9' ,
item10: name: 'Item 10' ,
,
cols: 2
,
computed:
columns: function()
let columns = [];
let mid = Math.ceil(Object.keys(this.items).length / this.cols);
for (let col = 0; col < this.cols; col++)
columns.push(Object.entries(this.items).slice(col * mid, col * mid + mid).map(entry => entry[1]));
return columns;
);
.container
display: flex;
border: 1px solid;
.col
margin: 10px;
border: 1px solid;
flex-grow: 1;
display: flex;
flex-direction: column;
.item-container
border: 1px solid;
padding: 5px;
margin: 5px;
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.9/vue.js"></script>
<script src="https://cdn.jsdelivr.net/npm/vue@2.5.17/dist/vue.min.js"></script>
<main>
<p><label>Columns:<label> <input type="number" v-model="cols"></p>
<div class="container">
<div class="col" v-for="column in columns">
<div class="item-container" v-for="(item, index) in Object.keys(column)">
column[item].name</div>
</div>
</div>
</main>
【讨论】:
以上是关于v-if inside v-for - 在两列中显示项目列表的主要内容,如果未能解决你的问题,请参考以下文章
在没有 v-if 和 v-for 的 Vue.js 中显示(添加、编辑)和删除多个列中的列表项