循环遍历Vue.js中的动态数组,然后根据对应的值将每个对象组件添加到单独组件中的div中?

Posted

技术标签:

【中文标题】循环遍历Vue.js中的动态数组,然后根据对应的值将每个对象组件添加到单独组件中的div中?【英文标题】:Loop through a dynamic array in Vue.js and then add each object component to divs in a separate component based on a corresponding value? 【发布时间】:2019-10-26 15:20:41 【问题描述】:

我正在尝试制作一个 Vue 应用程序,根据地区列出公司办公室。我有一个主主页视图、一个办公室组件和一个办公室项目组件。我在 office 组件中使用 v-for 来遍历 office 项目并显示它们。这样可以将它们全部列出。但是,我需要根据“区域”的值将办公项目分类到单独的 div 中。有5个地区。我无法弄清楚如何根据该单一值循环它们。

我知道如何将组件相互导入,但我正在尝试遍历 office 组件中的所有 office 项目。我的猜测是在循环中做一个循环,但是我需要另一个我缺少的组件吗?

办公用品组件:

<div class="office" :class="office.Region">
  <p>office.Name</p>
  <p>office.Address</p>
  <p>office.Country</p>
  <p>office.Region</p>
  <p>office.Email</p>
  <p>office.Phone</p>
</div>

办公室组件:

<div>
  <div v-for="office in offices" :key="office.name">
    <div class="office-container global" v-if="office.Region === 'Global'">
      <ul>
        <li><OfficeItem v-bind:office="office"/></li>
      </ul>
    </div>
    <div class="office-container north" v-if="office.Region === 'North America'">
      <ul>
        <li><OfficeItem v-bind:office="office"/></li>
      </ul>
    </div>
    <div class="office-container europe" v-if="office.Region === 'Europe, Middle East and Africa'">
      <ul>
        <li><OfficeItem v-bind:office="office"/></li>
      </ul>
    </div>         
    <div class="office-container asia" v-if="office.Region === 'Asia Pacific'">
      <ul>
        <li><OfficeItem v-bind:office="office"/></li>
      </ul>
    </div>
    <div class="office-container latin" v-if="office.Region === 'Latin America'">
      <ul>
        <li><OfficeItem v-bind:office="office"/></li>
      </ul>
    </div>
  </div>
</div>

硬编码的对象数组:

offices: [
    
      Name: "Corporate Headquarters",
      Address: "Suite 500, 698 West 10000 South, South Jordan, Utah 84095",
      Country: "USA",
      Region: "Global",
      Email: "contact@ivanti.com",
      Phone: "+1-888-253-6201"
    ,
    
      Name: "EMEA Headquarters",
      Address: "First Floor Europa House, Harcourt Street Dublin 2, D02 WR20",
      Country: "Ireland",
      Region: "Europe, Middle East and Africa",
      Email: "contact@ivanti.me",
      Phone: "+ 353 1 411 7100"
    ,
    
      Name: "India",
      Address: "Bagmane Tech Park, Unit No. 4A, Level 2 , Bangalore",
      Country: "India",
      Region: "Asia Pacific",
      Email: "contact@ivanti.com",
      Phone: ""
    ,
    
      Name: "Brazil",
      Address: "Borges de Figueiredo, 303 - 4th floor, Bairro Mooca, São Paulo, SP 03110-010",
      Country: "Brazil",
      Region: "Latin America",
      Email: "contact-brazil@ivanti.com",
      Phone: "+55 11 9 8136 0343"
    ,
    
      Name: "United States (Seattle)",
      Address: "1011 Western Ave SW #700, Seattle, WA 98104",
      Country: "United States",
      Region: "North America",
      Email: "contact@ivanti.com",
      Phone: "+1-206-274-4280"
    
]

我希望只有 5 个办公室容器 div,每个 div 中都有对应办公室的列表。但是,我得到了多个办公室容器(即两个北美 div)和其中的多个空 div

【问题讨论】:

您希望您的原始阵列按位置分块成办公室阵列? 或者让您的办公室按地区但按字母顺序排序? 我想让它们按区域排序,然后根据区域,放在对应的div中。它不必按字母顺序排列,我不确定制作单独的数组是否会使它过于复杂 目前这些项目都没有相同的Region ? 哦,我明白了,您想根据地区不同对待某些办公室。 【参考方案1】:

[...new Set(this.offices.map(o =&gt; o.Region))] 为您提供所有地区的列表。

您可以使用过滤方法遍历此列表并显示具有该区域的办公室:

officesOfRegion(region) 
  return this.offices.filter(o => o.Region === region)
,

Vue.config.productionTip = false;
Vue.config.devtools = false;

new Vue(
  el: '#hook',
  template: '#appTemplate',
  data: (
    offices: [
        Name: "Corporate Headquarters",
        Address: "Suite 500, 698 West 10000 South, South Jordan, Utah 84095",
        Country: "USA",
        Region: "North America",
        Email: "contact@ivanti.com",
        Phone: "+1-888-253-6201"
      ,
      
        Name: "EMEA Headquarters",
        Address: "First Floor Europa House, Harcourt Street Dublin 2, D02 WR20",
        Country: "Ireland",
        Region: "Europe, Middle East and Africa",
        Email: "contact@ivanti.me",
        Phone: "+ 353 1 411 7100"
      ,
      
        Name: "India",
        Address: "Bagmane Tech Park, Unit No. 4A, Level 2 , Bangalore",
        Country: "India",
        Region: "Asia Pacific",
        Email: "contact@ivanti.com",
        Phone: ""
      ,
      
        Name: "Brazil",
        Address: "Borges de Figueiredo, 303 - 4th floor, Bairro Mooca, São Paulo, SP 03110-010",
        Country: "Brazil",
        Region: "Latin America",
        Email: "contact-brazil@ivanti.com",
        Phone: "+55 11 9 8136 0343"
      ,
      
        Name: "United States (Seattle)",
        Address: "1011 Western Ave SW #700, Seattle, WA 98104",
        Country: "United States",
        Region: "North America",
        Email: "contact@ivanti.com",
        Phone: "+1-206-274-4280"
      
    ]
  ),
  computed: 
    regions() 
      return [...new Set(this.offices.map(o => o.Region))]
    
  ,
  methods: 
    officesOfRegion(region) 
      return this.offices.filter(o => o.Region === region)
    ,
    displayJson(o) 
      return JSON.stringify(o, null, 2);
    
  ,

)
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<script type="text/template" id="appTemplate">
  <div id="app">
    <div class="region" v-for="region in regions" :key="region">
      <hr>
      <h3 v-text="region"></h3>
      <ul>
        <li v-for="(office, i) in officesOfRegion(region)" :key="i">
          <pre v-html="displayJson(office)"></pre>
        </li>
      </ul>
    </div>
  </div>
</script>
<div id="hook"></div>

我没有查看您的标记,因为它无关紧要。正确排序数据后,您可以使用任何所需的标记。

这是你的标记:

Vue.config.productionTip = false;
Vue.config.devtools = false;

new Vue(
  el: '#hook',
  template: '#appTemplate',
  data: (
    offices: [
        Name: "Corporate Headquarters",
        Address: "Suite 500, 698 West 10000 South, South Jordan, Utah 84095",
        Country: "USA",
        Region: "North America",
        Email: "contact@ivanti.com",
        Phone: "+1-888-253-6201"
      ,
      
        Name: "EMEA Headquarters",
        Address: "First Floor Europa House, Harcourt Street Dublin 2, D02 WR20",
        Country: "Ireland",
        Region: "Europe, Middle East and Africa",
        Email: "contact@ivanti.me",
        Phone: "+ 353 1 411 7100"
      ,
      
        Name: "India",
        Address: "Bagmane Tech Park, Unit No. 4A, Level 2 , Bangalore",
        Country: "India",
        Region: "Asia Pacific",
        Email: "contact@ivanti.com",
        Phone: ""
      ,
      
        Name: "Brazil",
        Address: "Borges de Figueiredo, 303 - 4th floor, Bairro Mooca, São Paulo, SP 03110-010",
        Country: "Brazil",
        Region: "Latin America",
        Email: "contact-brazil@ivanti.com",
        Phone: "+55 11 9 8136 0343"
      ,
      
        Name: "United States (Seattle)",
        Address: "1011 Western Ave SW #700, Seattle, WA 98104",
        Country: "United States",
        Region: "North America",
        Email: "contact@ivanti.com",
        Phone: "+1-206-274-4280"
      
    ]
  ),
  computed: 
    regions() 
      return [...new Set(this.offices.map(o => o.Region))]
    
  ,
  methods: 
    officesOfRegion(region) 
      return this.offices.filter(o => o.Region === region)
    ,
    propsOf(o) 
      return Object.keys(o);
    
  ,
  
)
.office p 
  display: flex;

.office p strong 
  width: 100px;
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<script type="text/template" id="appTemplate">
  <div id="app">
    <div class="region" v-for="region in regions" :key="region">
      <hr>
      <hr>
      <h3>region</h3>
      <div v-for="(office, i) in officesOfRegion(region)" :key="i" class="office">
        <hr>
        <p v-for="prop in propsOf(office)"><strong>prop:</strong> office[prop]</p>
      </div>
    </div>
  </div>
</script>
<div id="hook"></div>

【讨论】:

我对 v-html 和 v-text 不太熟悉。如何在不实际显示文字 json 对象的情况下显示它? 我添加了一个带有您的标记的版本。 v-textv-html 只需将元素的内容(作为文本或作为 html)设置为提供的值。作为旁注,你正在做:class="office.region"。这将输出class="Europe, Middle East and Africa"。您确定要在元素上使用逗号和空格的类吗?这基本上会导致多个类。在一般的编码设计原则上,我强烈建议不要这样做。 @Holly,还请注意,我在第二个示例中使用了一种列出所有对象属性的方法:Object.keys(obj)【参考方案2】:

看起来你的模板中唯一改变的是 OfficeItem 组件周围的类

为了让您的代码不那么干燥,请尝试在OfficeItem 组件中应用该条件逻辑,如下所示。

// OfficeItem.vue
<template>
  <li :class="['office-container', getRegionClass(office.Region)]">office.Region</li>
</template>

<script>
const regional_classes = 
  A: 'class_a and-another-A-class',
  B: 'class_b and-another-B-class',
  C: 'class_c and-another-C-class',
  D: 'class_d and-another-D-class',
  Z: 'class_z and-another-Z-class'


export default 
  name: "OfficeItem",
  props: 
    office: Object
  ,
  methods: 
    getRegionClass(region) 
      return regional_classes[region] || ''
    
  
;
</script>
或者,有一个switch 语句接受Region 并返回switch 中遇到的任何情况的字符串。

在这个场景中,虽然我觉得 regional_class 对象更具可读性/可维护性。

在您的Offices 组件中,只需将office 对象传递给您的Officeitem,如下所示

// Offices.vue
<template>
  <div>
    <ul :key="`$regionName_$index`" v-for="(region, regionName, index) in officesByRegion">
      <h1>Region regionName</h1>
      <OfficeItem v-for="office in region" :key="office.Region" :office="office"/>
    </ul>
  </div>
</template>

<script>
export default 
  name: "Offices",
  data() 
    return 
      offices: [
         Region: "A" ,
         Region: "B" ,
         Region: "C" ,
         Region: "D" ,
         Region: "Z" ,
         Region: "A" ,
         Region: "B" ,
         Region: "A" ,
         Region: "B" ,
         Region: "A" ,
         Region: "Z" ,
         Region: "C" ,
         Region: "D" ,
         Region: "E" 
      ]
    ;
  ,
  computed: 
    officesByRegion() 
      const obj = ;
      this.offices.forEach(o => 
        if (o.Region in obj) obj[o.Region].push(o);
        else obj[o.Region] = [o];
      );
      return obj;
    
  
;
</script>

我希望这会有所帮助。或者至少对动态 css 类应用程序有所了解。 :-)

【讨论】:

来自问题:我需要根据“Region”的值将办公物品分类到单独的div中。也许您不应该假设所有地区都有 1 个办事处。问题确实说:“动态数组”。这就是为什么你应该期望它会改变。数据集只是一个例子。 说实话,我一直在努力弄清楚 OP 到底需要什么。在示例中,Holly 需要在每次迭代中添加一个特定于区域的 CSS 类 - 而不是将数组按区域分类然后渲染。 我觉得很简单。我们不是来帮助霍莉的。我们在这里帮助任何可能来这里寻找类似案例解决方案的人。这稍微简化了一些事情,你不同意吗? 我觉得很简单。我们不是来帮助霍莉的。我们在这里帮助任何可能来这里寻找类似案例解决方案的人。这稍微简化了一些事情,你不同意吗? @FrancisLeigh 抱歉,如果不清楚。我以为是。就像我说的,我只需要拿一个办公对象,找到它的区域,然后附加或放置在与该区域对应的 div 中。这里的数据是硬编码的,但将来自具有更多办公室的 api。 div 将有一个但很可能不止一个办公室。这就是为什么我认为我需要遍历每个办公对象以在遍历办公对象数组的循环中找到它的区域

以上是关于循环遍历Vue.js中的动态数组,然后根据对应的值将每个对象组件添加到单独组件中的div中?的主要内容,如果未能解决你的问题,请参考以下文章

vue.js 中的v-for可以将遍历出来的值放入标签属性吗

如何在vue js中循环遍历数组中的图像数组

vue之v-for

Js 怎么遍历json对象所有key及根据动态key获取值

怎样用for循环动态遍历json数组

vue中的v-for循环指令使用