Vue.js:使用计算的条件渲染数组属性

Vue.js: Conditional Rendering Array Using Computed Property

我是 Vue 的新手,过去几个小时一直在研究如何在方法和计算属性中使用条件逻辑来创建生日组件的实践项目。我看到其他人在他们的计算 属性 中使用 if/else 语句,但我收到 Unexpected side effect in "displayDays" computed property 错误消息。

我的 objective 是在通过选项列表(或者在本例中,纽扣)。当用户点击生日月份时,我希望该月的天数列表能够在与该月关联的模板中显示适当的日期数组。

这就是我被困的地方。我最初尝试在方法单击事件 selectedMonth() 上添加数组值,经过一些研究,我意识到我需要使用计算属性来更改天数数组中的数据,就像我想要的那样。但是,在多次尝试将 if/else 语句 运行 无误地放入计算部分后,我不确定我遗漏了什么。

非常感谢任何帮助或指导!

下面是我的代码:

<template>
  <div>
    <div id="months">
      <label class="uppercase">Month</label>
      <label>Select a month</label>
      <div>
        <button
          class="month"
          v-for="month in months"
          :key="month.text" 
          :value="month.value"
          v-on:click="selectedMonth(month)"
        >{{ month.text }}</button>
      </div>
    </div>

    <div id="days">
      <label class="uppercase">Day</label>
      <label>Select a day</label>
      <div>
        <button
          class="day"
          v-for="day in displayDays"
          :key="day" 
          v-on:click="selectedDay(day)"
        >{{ day }}</button>
      </div>
    </div>

    <div id="year">
      <label class="uppercase">Input Year</label>
      <label aria-label="Four Digit Year">Four Digit YYYY</label>
        <input
          type="text"
          id="dobYear"
          name="year"
          maxlength="4"
        >
    </div>

    <button>
      Submit DOB
    </button>

  </div>
</template>

<script>
  export default {
    name: 'birthday',
    data() {
      return {
        months: [
          {text: 'Jan', value: '01'},
          {text: 'Feb', value: '02'},
          {text: 'Mar', value: '03'},
          {text: 'Apr', value: '04'},
          {text: 'May', value: '05'},
          {text: 'Jun', value: '06'},
          {text: 'Jul', value: '07'},
          {text: 'Aug', value: '08'},
          {text: 'Sep', value: '09'},
          {text: 'Oct', value: '10'},
          {text: 'Nov', value: '11'},
          {text: 'Dec', value: '11'}
        ],
        days: [],
        year: '',
        active: true,
        birthday:['','','',],
      }
    },
    methods: {
      selectedMonth(month) {
        // console.log('clicked '+ month);
        this.birthday[0] = month.value;
        this.birthday[1] = '';
        console.log(this.birthday);
      },
      selectedDay(day) {
        // console.log('clicked '+ day);
        this.birthday[1] = day;
        console.log(this.birthday);
        this.birthDay = day;
      },
      submittedYear(year) {
        this.birthday[2] = year;
        console.log(this.birthday);
      }
    },
    computed: {
      displayDays() {
        if(this.month === 'Feb') {
          return this.days = ['01','02','03','04','05','06','07','08','09','10',
          '11','12','13','14','15','16','17','18','19','20',
          '21','22','23','24','25','26','27','28', '29']
        } else if(this.month === 'Apr' || this.month === 'Jun' || this.month === 'Sep' || this.month === 'Nov') {
          return this.days = ['01','02','03','04','05','06','07','08','09','10',
          '11','12','13','14','15','16','17','18','19','20',
          '21','22','23','24','25','26','27','28','29','30']
        } else {
          return this.days = ['01','02','03','04','05','06','07','08','09','10',
          '11','12','13','14','15','16','17','18','19','20',
          '21','22','23','24','25','26','27','28','29','30','31']
        }
      }
    }
  }

</script>

<style scoped>
#months, #days, #year {
    border: 0.125rem solid #e5e5e5;
    border-radius: 0.5rem;
    margin-bottom: 0.625rem;
}

#months > div, #days > div, #year {
  display: flex;
  flex-wrap: wrap;
  flex-direction: row;
  gap: 0.75rem 0.4375rem;
  justify-content: center;
  padding: 10% 11% 10%;
  box-sizing: border-box;
}

button {
  text-align: center;
  width: 5.0625rem;
  height: 2.625rem;
  background: #fff;
  border-radius: 6.25rem;
  border: 0.125rem solid #5500B3;
  line-height: 2.4rem;
}

#days > div {
  justify-content: left;
}

#days > div > button {
  border-radius: 10rem;
  width: 2.625rem;
}

#months > div > button:hover, #days > div > button:hover {
  cursor: pointer;
  background: #efefef;
}

#year input {
  font-size: 1.125rem;
  font-weight: 400;
  border: #ececec;
  box-sizing: border-box;
  padding: 0.3125rem 0.875rem 0rem;
  background: #ececec solid;
  border-radius: 0.625rem;
  height: 3.75rem;
  border-style: none;
}

.uppercase {
  text-transform: uppercase;
}
</style>

问题出在计算的 属性 部分。

您不应该简单地在 displayDays 计算方法中为 this.days 分配所需的数组。相反,您必须 return 从计算的 属性.

中获取所需的数组

此外,当计算 属性 中的任何参数发生变化时,计算机属性将被重新评估。这里您在计算的 属性 中使用了 this.month,但是您没有在代码中的任何地方更新它,因此您的计算的 属性 将永远不会被重新计算。因此,您必须在 selectedMonth 方法中将 this.month 的值分配为 this.month = month.text;。一旦 this.month 的值发生变化,您计算的 属性 将使用 this.month 的新值再次评估。

工作Fiddle

new Vue({
    el: '#app',
    name: 'birthday',
    data() {
        return {
            months: [
                { text: 'Jan', value: '01' },
                { text: 'Feb', value: '02' },
                { text: 'Mar', value: '03' },
                { text: 'Apr', value: '04' },
                { text: 'May', value: '05' },
                { text: 'Jun', value: '06' },
                { text: 'Jul', value: '07' },
                { text: 'Aug', value: '08' },
                { text: 'Sep', value: '09' },
                { text: 'Oct', value: '10' },
                { text: 'Nov', value: '11' },
                { text: 'Dec', value: '11' }
            ],
            days: [],
            year: '',
            active: true,
            birthday: ['', '', '',],
            month: null,
        }
    },
    methods: {
        selectedMonth(month) {
            // console.log('clicked '+ month);
            this.birthday[0] = month.value;
            this.birthday[1] = '';
            console.log(this.birthday);
            this.month = month.text;
        },
        selectedDay(day) {
            // console.log('clicked '+ day);
            this.birthday[1] = day;
            console.log(this.birthday);
            this.birthDay = day;
        },
        submittedYear(year) {
            this.birthday[2] = year;
            console.log(this.birthday);
        }
    },
    computed: {
        displayDays() {
            if (this.month === 'Feb') {
                return ['01', '02', '03', '04', '05', '06', '07', '08', '09', '10',
                    '11', '12', '13', '14', '15', '16', '17', '18', '19', '20',
                    '21', '22', '23', '24', '25', '26', '27', '28', '29']
            } else if (this.month === 'Apr' || this.month === 'Jun' || this.month === 'Sep' || this.month === 'Nov') {
                return ['01', '02', '03', '04', '05', '06', '07', '08', '09', '10',
                    '11', '12', '13', '14', '15', '16', '17', '18', '19', '20',
                    '21', '22', '23', '24', '25', '26', '27', '28', '29', '30']
            } else {
                return ['01', '02', '03', '04', '05', '06', '07', '08', '09', '10',
                    '11', '12', '13', '14', '15', '16', '17', '18', '19', '20',
                    '21', '22', '23', '24', '25', '26', '27', '28', '29', '30', '31']
            }
        }
    }
})
#months, #days, #year {
    border: 0.125rem solid #e5e5e5;
    border-radius: 0.5rem;
    margin-bottom: 0.625rem;
}

#months > div, #days > div, #year {
  display: flex;
  flex-wrap: wrap;
  flex-direction: row;
  gap: 0.75rem 0.4375rem;
  justify-content: center;
  padding: 10% 11% 10%;
  box-sizing: border-box;
}

button {
  text-align: center;
  width: 5.0625rem;
  height: 2.625rem;
  background: #fff;
  border-radius: 6.25rem;
  border: 0.125rem solid #5500B3;
  line-height: 2.4rem;
}

#days > div {
  justify-content: left;
}

#days > div > button {
  border-radius: 10rem;
  width: 2.625rem;
}

#months > div > button:hover, #days > div > button:hover {
  cursor: pointer;
  background: #efefef;
}

#year input {
  font-size: 1.125rem;
  font-weight: 400;
  border: #ececec;
  box-sizing: border-box;
  padding: 0.3125rem 0.875rem 0rem;
  background: #ececec solid;
  border-radius: 0.625rem;
  height: 3.75rem;
  border-style: none;
}

.uppercase {
  text-transform: uppercase;
}
<script src="https://cdn.jsdelivr.net/npm/vue@^2"></script>
<div id="app">
    <div>
        <div id="months">
            <label class="uppercase">Month</label>
            <label>Select a month</label>
            <div>
                <button class="month" v-for="month in months" :key="month.text" :value="month.value"
                    v-on:click="selectedMonth(month)">{{ month.text }}</button>
            </div>
        </div>

        <div id="days">
            <label class="uppercase">Day</label>
            <label>Select a day</label>
            <div>
                <button class="day" v-for="day in displayDays" :key="day" v-on:click="selectedDay(day)">{{ day
                    }}</button>
            </div>
        </div>

        <div id="year">
            <label class="uppercase">Input Year</label>
            <label aria-label="Four Digit Year">Four Digit YYYY</label>
            <input type="text" id="dobYear" name="year" maxlength="4">
        </div>

        <button>
            Submit DOB
        </button>

    </div>
</div>