Vue 2 按乐器名称列出乐队成员但只显示一次乐器名称

Vue 2 list band members by instrument name but only display the instrument name once

我可以按乐器名称列出乐队成员,但只想显示一次乐器名称,而不是显示巴松管组中每个人的乐器名称。我的想法是提取一组不同的仪器名称,并做一个 v-if 将成员的仪器名称与迭代设置值进行比较,并且仅当成员的数据 属性 instrumentName 与当前值匹配时才显示该成员仪器名称设置。使用下面的代码,我得到一个错误“instNames is not defined”。我仍在学习 Vue 和 Nuxt,并试图摆脱我网站的原始平台 WebMatrix。我需要的另一件事是将一个仪器文件名(图片)附加到每个不同的仪器名称。非常感谢任何帮助!

<template>
  <div class="block bg-blue-200 w-96 p-6 m-auto">
    <table>
      <tr v-for="inst in instNames">
        <td>{{ inst.instrumentName }} <img :src="'/images/' + inst.instrumentFilename" >      
        <td v-for="member in members" :key="member.id">      
          <div v-if="member.instrumentName == inst.instrumentName"> </div>
        
          <div>{{ member.firstname }} {{ member.lastname }} </div>
          <div v-if="$auth.loggedIn" class="block">
            <p v-if="!member.email == ' '" class="ml-10"> Email: {{ member.email }} </p>
            <p v-if="!member.telephone == ' '" class="ml-10"> Home: {{ member.telephone }} </p>
            <p v-if="!member.telephone2 == ' '" class="ml-10">Cell: {{ member.telephone2 }}</p>
            <p v-if="!member.street == ' '" class="ml-10">Address: {{ member.street}}</p>          
            <p v-if="!member.city == ' '" class="ml-28">{{ member.city}}, {{ member.zip}}</p>
          </div>
        </td>
      </tr>
    </table>      
  </div>
  
</template>

<script>
export default {
  async asyncData(context){
    const { data } = await context.$axios.get('/api/members')        
    return {
      members : data     
    }
  },
 
  computed: {
    instNames: function() {      
      instNames = [...new Set(this.members.map(x => x.instrumentName))]
      return instNames
    } 
  } 
}
</script>

您的计算 属性 尝试分配 instNames,但未在任何地方声明。但是,您实际上并不需要局部变量,因为它未被使用。您可以 return 计算出的集合:

export default {
  computed: {
    instNames: function() {
      //instNames = [...new Set(this.members.map(x => x.instrumentName))]
      //^^^^^^^^^ ❌ not declared

      // Option 1: Declare it with `let` or `const`
      const instNames = [...new Set(this.members.map(x => x.instrumentName))]
      return instNames

      // Option 2: Just return the calculation
      return [...new Set(this.members.map(x => x.instrumentName))]
    } 
  } 
}

但是您的模板尝试从计算的 instNames(字符串数组,而不是对象)渲染 instrumentNameinstrumentFilename。假设这些值来自 this.members,您可以将计算值更新为 return 这些字段:

export default {
  computed: {
    instNames: function() {
      const instName = this.members.map(x => ({
        instrumentName: x.instrumentName,
        instrumentFilename: x.instrumentFilename,
      }))

      // remove duplicates here ...
      
      return instName
    } 
  } 
}

最后,您的模板 v-if 条件未正确检查非空字符串。对于 !member.email == ' '! 运算符具有优先权,它会检查 member.email 是否存在虚假值,即 String 的空字符串。然后它将它与单个 space 进行比较,后者始终是 false,因为 space 不是假的。您可以用一个简单的真值检查来代替整个比较:

<p v-if="member.email">...</p>
<p v-if="member.telephone">...</p>
<p v-if="member.telephone2">...</p>
<p v-if="member.street">...</p>
<p v-if="member.city">...</p>

以上评论非常宝贵,非常感谢。不过,我的 return 数组的唯一性仍然存在问题;显然,一个 Set 将对一个对象的多次引用视为唯一。所以我最终使用了这段代码:

computed: {
    instNames: function() {      
    
      const instName = this.members.map
      (({ instrumentName, instrumentFilename }) => ({ instrumentName, instrumentFilename}))
      const instNameArray = []
      const instNameSet = new Set()
      for (const object of instName) {
        const objectJSON = JSON.stringify(object)
        if(!instNameSet.has(objectJSON)) {
          instNameArray.push(object)
        }
        instNameSet.add(objectJSON)
      }
      console.log(instNameArray)
         
      return instNameArray
    } 
  }