首页 > 解决方案 > v-for 中每个组件的唯一内容

问题描述

程序说明:我正在用 Vue.js 制作一个简单的时间表程序。该页面有一个“日历”(一个包含 7 列的表格,其中每一列对应一个特定日期)和每个日历列底部的按钮。单击按钮时,模式应弹出其正文内容中的特定日期。模式的正文内容中的日期应与放置按钮的列标题中的日期相同。forward单击或backward按钮也可以更改日期。单击forward所有日期时,将向前移动一天。如果backward所有日期向后移动一天。

程序的方法:我有一个App.vue用于 modal 的父组件和一个子组件modal.vue。在父组件中,作为属性之一,我有一个数组dateArr,其中包含以下格式的 7 个不同日期:['9/11/21', '9/12/21', ..., '15/11/21']. 正在调用App.vue挂载方法,该方法用日期填充属性。单击并正在更改并且正在触发方法。表的第一行包含日期,因此我创建它并遍历每个getDatesArraydateArrbackwardforward currentOffsetgetDatesArrayv-fordatedateArr. 表的主体由每列 3 行组成。每列的最后一行包含一个唯一的按钮和一个模式。在最后一行中,我想将每个组件绑定到特定日期,所以我再次遍历每个datein dateArr。模态组件中有一个插槽,我在其中放置了 unique datefrom dateArr。单击按钮时,模态的可见性随change方法而变化。

问题:一切正常,但是,无论我单击什么按钮,date模态组件的内容 ( ) 都保持不变:15/11/21,这是数组的最后一个元素。该程序的目的是date在每个模态组件内拥有唯一的内容 (),核心属性 ( dateArr) 是动态的。我已经尝试对这个问题实施不同的解决方案,但没有一个有用。我将非常感谢任何帮助!

App.vue

<template>
  <table class = 'dataFrame'>
    <thead>
      <tr>
        <th v-for="item in dayArr" :key="item.id">
          {{item}}
        </th>
      </tr>
    </thead>
    <tbody>
      <tr v-for="index in [1,2,3]" :key="index">
        <td v-for="item_index in dayArr.length" :key="item_index">
          Dummy content
        </td>
      </tr>
      <tr>
        <td v-for="date in dayArr" :key="date.id">
          <button @click="change">+</button>
          <modal-component @changevisibility="change" v-if="modalToggled">
            <p>{{ date }}</p>
          </modal-component>
        </td>
      </tr>
    </tbody>
  </table>
  <div class="buttonSection">
      <button @click="currentOffset --" class="back" v-show="currentOffset >= -7">forward</button>
      <button @click="currentOffset ++" class="forward" v-show="currentOffset <= 7">backward</button>
  </div>
</template>

<script>
import basecard from './components/card.vue'
import navbarComponent from './components/menu.vue'
import modalComponent from './components/modal.vue'

export default {
  data() {
            return {
                currentOffset: 0,
                modalToggled : false,
                dayArr: []
            }
        },
  methods: {
      change() {
        this.modalToggled = !this.modalToggled
      },
      getDatesArray() {
          let date = new Date();
          date.setDate(date.getDate() + this.currentOffset);
          let dayArr = [];
          for (let i = 0; i < 7; i++) {      
            let customDateArray = new Intl.DateTimeFormat('en-GB', { day: 'numeric', month: 'short', year: 'numeric', hour: 'numeric', minute: 'numeric' }).formatToParts(date)   
            let dateParts = {}
            customDateArray.map(({type, value}) => {
              dateParts[type] = value
            })
            dayArr.push(`${dateParts.day}/${date.getMonth()+1}/${dateParts.year.slice(-2)}`)
            date.setDate(date.getDate() + 1);
          }
          this.dayArr = dayArr
      }
  },
  mounted () {
    this.getDatesArray()
  },
  watch: {
    currentOffset () {
      this.getDatesArray()
    }
  },
  name: 'App',
  components: {
    modalComponent
  }
}
</script>

<style>
  #app {
    display: flexbox;
    font-family: Avenir, Helvetica, Arial, sans-serif;
    -webkit-font-smoothing: antialiased;
    -moz-osx-font-smoothing: grayscale;
    color: #2c3e50
  }

  .dataFrame {
    border: 2px solid;
    width: 100%;
    border-color: #2c3e50;
  }

  .buttonSection {
    margin-top: 1rem;
    width: 100%;
    max-height: 100%;
  }

  .back {
    float: left;
  }

  .forward {
    float: right;
  }
</style>

modal.vue

<template>
    <div class="modal">
        <div class="modal-content">    
            <slot></slot>      
            <button @click="changeVisibilityFromComponent">
                    <span class="close">Close &times;</span>
            </button>
        </div>
    </div>
</template>

<script>
export default {
    name: 'modalComponent',
    methods: {
        changeVisibilityFromComponent () {
            this.$emit('changevisibility')
        },
    }
}
</script>

<style scoped>
.modal {
  position: fixed; 
  z-index: 1; 
  left: 0;
  top: 0;
  width: 100%; 
  height: 100%; 
  overflow: auto; 
  background-color: rgb(0,0,0);
  background-color: rgba(0,0,0,0.4); 
}

.modal-content {
  background-color: #fefefe;
  margin: 15% auto; 
  padding: 20px;
  border: 1px solid #888;
  width: 80%; 
}

.close {
  color: #aaa;
  float: right;
  font-size: 28px;
  font-weight: bold;
}

.close:hover,
.close:focus {
  color: black;
  text-decoration: none;
  cursor: pointer;
}
</style>

标签: javascriptvue.js

解决方案


我想到的第一件事是传递一个索引来改变函数,从而计算一些独立于 v-for 循环的值:

<td v-for="(date, index) in dayArr" :key="date.id">
  <!-- pass index to change method -->
  <button @click="change(index)" :id="index">+</button>
  <modal-component @changevisibility="change(index)" v-if="modalToggled">
    <!-- to slot pass the new variable -->
    <!-- remember to add it to data() with some init value like null -->
    <p>{{ currentDate }}</p>
  </modal-component>
</td>

...

methods: {
    change(index) {
      // set currentDate value each time change method is being run
      this.currentDate = this.dayArr[index];
      this.modalToggled = !this.modalToggled
    },
    ...
}

您遇到问题的原因是 v-for 呈现项目列表并以与以下代码相同的方式设置变量:

let x = 0;
for (i = 0; i < 10; i++) {
    x = i;
}
console.log(x); // this will always console out x = 9

相反,事件处理(如@click)创建一个监听 DOM 事件并在每次触发事件时运行一个方法的指令。至少我是这么理解的……</p>


推荐阅读