关于vue侦听器赋值的问题

我在侦听器中设置了这样一个逻辑:监听日期选择器中绑定的日期,如果选中的日期和当前时间new Date()相同,则根据当前时间所处时段,给单选框的v-model赋值“上午”或“下午”。但是每当我赋值成功之后,单选框组就无法操作了,其他的单选框按钮无法被选中。

img

            <div class="singleRow">
                <van-field readonly clickable v-model="formData.startTime" placeholder="开始时间"
                    label="开始时间:" label-width="70px" @click="showPicker = true" />
                <van-radio-group style="min-width: 150px;" v-model="formData.startShiduan" direction="horizontal">
                    <van-radio name="上午" value="上午">上午</van-radio>
                    <van-radio name="下午" value="下午">下午</van-radio>
                </van-radio-group>
            </div>
            <div class="singleRow">
                <van-field readonly clickable v-model="formData.endTime" placeholder="结束时间"
                    label="结束时间:" label-width="70px" @click="showPicker2 = true" />
                <van-radio-group style="min-width: 150px;" v-model="formData.endShiduan" direction="horizontal">
                    <van-radio name="上午" value="上午">上午</van-radio>
                    <van-radio name="下午" value="下午">下午</van-radio>
                </van-radio-group>
            </div>
        watch: {
            formData: {
                handler: function(newValue, oldValue) {
                    const startDate = new Date(newValue.startTime).setHours(0, 0, 0, 0);
                    const endDate = new Date(newValue.endTime).setHours(0, 0, 0, 0);
                    const todayDate = new Date().setHours(0, 0, 0, 0);
                    // 如果开始时间是当天
                    if (startDate == todayDate) {
                        const hours = new Date().getHours();
                        if (hours >= 0 && hours < 12) {
                            this.formData.startShiduan = "上午";
                        } else if (hours >= 12 && hours < 24) {
                            this.formData.startShiduan = "下午";
                        }
                    }
                    // 如果结束时间是当天
                    if (endDate == todayDate) {
                        const hours = new Date().getHours();
                        if (hours >= 0 && hours < 12) {
                            this.formData.endShiduan = "上午";
                        } else if (hours >= 12 && hours < 24) {
                            this.formData.endShiduan = "下午";
                        }
                    }
                },
                deep: true,
                immediate: true
            }
        }

代码如上,请各位帮忙看看问题出在哪里

貌似看着没啥大问题,不过你van-radio中的value没用可以删了,还有其实可以不用watch,你应该是点击输入框后弹出日期选择器组件的吧?用组件的confirm事件不就可以进行你的判断了吗,为啥要用watch

以下内容部分参考ChatGPT模型:
问题的原因是在侦听器中给单选框的v-model赋值后,会触发单选框的change事件,从而又触发了formData的更新,形成了无限循环,导致单选框无法操作。

解决思路是在给单选框的v-model赋值之前,先判断当前选中的值是否和要赋的值相同,如果相同则不赋值,避免触发change事件。可以使用Vue.set()方法来实现赋值。示例如下:

if (this.formData.startShiduan !== '上午') {
  Vue.set(this.formData, 'startShiduan', '上午');
}

另外,也可以使用计算属性来实现类似的逻辑,避免在侦听器中进行复杂的逻辑处理。具体实现可以参考如下代码:

computed: {
  startShiduan: function() {
    const startDate = new Date(this.formData.startTime).setHours(0, 0, 0, 0);
    const todayDate = new Date().setHours(0, 0, 0, 0);
    if (startDate == todayDate) {
      const hours = new Date().getHours();
      if (hours >= 0 && hours < 12) {
        return '上午';
      } else if (hours >= 12 && hours < 24) {
        return '下午';
      }
    }
    return this.formData.startShiduan;
  },
  endShiduan: function() {
    const endDate = new Date(this.formData.endTime).setHours(0, 0, 0, 0);
    const todayDate = new Date().setHours(0, 0, 0, 0);
    if (endDate == todayDate) {
      const hours = new Date().getHours();
      if (hours >= 0 && hours < 12) {
        return '上午';
      } else if (hours >= 12 && hours < 24) {
        return '下午';
      }
    }
    return this.formData.endShiduan;
  }
}

然后在模板中使用计算属性即可:

<van-radio-group style="min-width: 150px;" v-model="startShiduan" direction="horizontal">
  <van-radio name="上午" value="上午">上午</van-radio>
  <van-radio name="下午" value="下午">下午</van-radio>
</van-radio-group>

如果我的建议对您有帮助、请点击采纳、祝您生活愉快

不要监听整个对象啊!就监听开始时间和结束时间就好了

watch: {
    "formData.startTime"(newValue){
        const startDate = new Date(newValue).setHours(0, 0, 0, 0);
        const todayDate = new Date().setHours(0, 0, 0, 0);
        // 如果开始时间是当天
        if (startDate == todayDate) {
          const hours = new Date().getHours();
          if (hours >= 0 && hours < 12) {
            this.formData.startShiduan = "上午";
          } else if (hours >= 12 && hours < 24) {
            this.formData.startShiduan = "下午";
          }
      }
    },
    "formData.endTime"(newValue){
        const endDate = new Date(newValue).setHours(0, 0, 0, 0);
        const todayDate = new Date().setHours(0, 0, 0, 0);
        // 如果结束时间是当天
      if (endDate == todayDate) {
          const hours = new Date().getHours();
          if (hours >= 0 && hours < 12) {
            this.formData.endShiduan = "上午";
          } else if (hours >= 12 && hours < 24) {
            this.formData.endShiduan = "下午";
          }
      }
    }
  },
不知道你这个问题是否已经解决, 如果还没有解决的话:
  • 这有个类似的问题, 你可以参考下: https://ask.csdn.net/questions/7630746
  • 我还给你找了一篇非常好的博客,你可以看看是否有帮助,链接:vue中v-model绑定的变量赋值给了另一个变量后,两个变量同时改变
  • 除此之外, 这篇博客: 教你从零写vue日历组件中的 2.3 将月份选择器和日历组件组合使用 部分也许能够解决你的问题, 你可以仔细阅读以下内容或者直接跳转源博客中阅读:

    效果示意图:
    在这里插入图片描述
    在这里插入图片描述

    组合代码如下:

    <template>
      <div>
        <a-card>
          <!-- 操作栏 -->
          <a-row type="flex" justify="space-around">
            <a-col :span="12">
              <!-- 月份选择器 -->
              <monthpicker @changeMonth="changeMonth"></monthpicker>
            </a-col>
            <a-col :span="12"></a-col>
          </a-row>
          <!-- 日历栏 -->
          <a-row class="calendar-con">
            <calendar :time="time"></calendar>
          </a-row>
        </a-card>
      </div>
    </template>
    
    <script>
    // 月份选择器
    import Monthpicker from './components/Monthpicker.vue'
    // 日历组件
    import Calendar from './components/Calendar.vue'
    export default {
      components: {
        monthpicker: Monthpicker,
        calendar: Calendar
      },
      data() {
        return {
          time: {
            year: new Date().getFullYear(),
            month: new Date().getMonth()
          }
        }
      },
      created() {},
      methods: {
        // 修改月份
        changeMonth(time) {
          console.log('time', time)
          this.time = time
        }
      }
    }
    </script>
    <style lang="less" scoped>
    .month-con {
      font-weight: 700;
      font-size: 18px;
      .month {
        margin: 0 10px;
      }
    }
    .calendar-con {
      margin-top: 20px;
    }
    </style>
    
    

    通过changeMonth事件,将月份选择器的月份传递给日历组件,这样就完成了一个简单的能够修改月份的日历组件了。

  • 您还可以看一下 马金聚老师的Vue全家桶技术+商城项目实战+源码解析课程中的 Vue指令之v-model双向数据绑定小节, 巩固相关知识点

如果你已经解决了该问题, 非常希望你能够分享一下解决方案, 写成博客, 将相关链接放在评论区, 以帮助更多的人 ^-^

以下答案由GPT-3.5大模型与博主波罗歌共同编写:
根据你的代码,这里出现的问题可能是在 formData 中使用的深度观察导致了 radio-group 的不可用。

你可以尝试添加以下代码,减小 formData 对象内部的观察深度,从而防止其影响其他的组件。

watch: {
  "formData.startTime": function (newValue, oldValue) { /* your code here */},
  "formData.endTime": function (newValue, oldValue) { /* your code here */}
}

最终的代码如下:

<template>
  <div>
    <div class="singleRow">
      <van-field
        readonly
        clickable
        v-model="formData.startTime"
        placeholder="开始时间"
        label="开始时间:"
        label-width="70px"
        @click="showPicker = true"
      />
      <van-radio-group
        style="min-width: 150px;"
        v-model="formData.startShiduan"
        direction="horizontal"
      >
        <van-radio name="上午" value="上午">上午</van-radio>
        <van-radio name="下午" value="下午">下午</van-radio>
      </van-radio-group>
    </div>
    <div class="singleRow">
      <van-field
        readonly
        clickable
        v-model="formData.endTime"
        placeholder="结束时间"
        label="结束时间:"
        label-width="70px"
        @click="showPicker2 = true"
      />
      <van-radio-group
        style="min-width: 150px;"
        v-model="formData.endShiduan"
        direction="horizontal"
      >
        <van-radio name="上午" value="上午">上午</van-radio>
        <van-radio name="下午" value="下午">下午</van-radio>
      </van-radio-group>
    </div>
  </div>
</template>

<script>
  export default {
    name: "MyComponent",
    data() {
      return {
        formData: {
          startTime: "",
          endTime: "",
          startShiduan: "",
          endShiduan: ""
        }
      };
    },
    watch: {
      "formData.startTime": function(newValue, oldValue) {
        const startDate = new Date(newValue).setHours(0, 0, 0, 0);
        const endDate = new Date(this.formData.endTime).setHours(0, 0, 0, 0);
        const todayDate = new Date().setHours(0, 0, 0, 0);
        // 如果开始时间是当天
        if (startDate == todayDate) {
          const hours = new Date().getHours();
          if (hours >= 0 && hours < 12) {
            this.formData.startShiduan = "上午";
          } else if (hours >= 12 && hours < 24) {
            this.formData.startShiduan = "下午";
          }
        }
      },
      "formData.endTime": function(newValue, oldValue) {
        const startDate = new Date(this.formData.startTime).setHours(0, 0, 0, 0);
        const endDate = new Date(newValue).setHours(0, 0, 0, 0);
        const todayDate = new Date().setHours(0, 0, 0, 0);
        // 如果结束时间是当天
        if (endDate == todayDate) {
          const hours = new Date().getHours();
          if (hours >= 0 && hours < 12) {
            this.formData.endShiduan = "上午";
          } else if (hours >= 12 && hours < 24) {
            this.formData.endShiduan = "下午";
          }
        }
      }
    }
  };
</script>

这样应该可以解决你的问题,但是这种做法有一个问题,就是当 formData 的任何一个属性发生变化时,都要进行计算和触发视图更新,这可能会影响性能。因此,更好的做法是将计算和逻辑代码单独提取出来,然后在参数变化时调用它们进行更新。
如果我的回答解决了您的问题,请采纳!