el-calendar 日历点击事件获取不到问题
前言
有一个需求,需要展示一个日历,打开的时候需要获取到日历上面的全部日期拥有的数据,同时还需要对指定的某一天进行数据展示编辑新增,对于这个需求梳理出对应的逻辑:
- 日历被通过点击触发的时候,需要调用接口获取到所有的数据
- 将获取的数据使用
el-calendar
的自定义内容,也就是插槽进行展示- 点击某一天的时候,将该内容的数据在日历下发的表单数据进行展示(这里不是本章关注的内容)
- 获取到点击的天数的时候,还可以对当日下面的表单数据进行添加修改操作(这里不是本章关注的内容)
bug的产生
在其他接口以及逻辑进行调用和编写的时候一切还是很顺利的,但是在我点击日历的某一天的时候就出现了问题,我慢慢剖析:
- 首先来看主要代码内容,其中关于接口调用等方面我进行了省略:
<el-calendar>
<div slot="dateCell" slot-scope="{data}">
<div :class="data.isSelected ? 'is-selected' : ''" @click="allcalendar(data)">
<div class="day">
{{ data.day.split('-').slice(1).join('-') }}
{{ data.isSelected ? '✔️' : '' }}
</div>
<div class="info" style="display: flex">
<div v-for="(i, index) in dateInfo[data.day]" :key="index">{{ i ? '✨' : '' }}</div>
</div>
</div>
</div>
</el-calendar>
这里稍微介绍下,div class="info"
这里面的内容可以不过多说明,里面就是通过展示日历的时候调用接口获取的数据,data.day
就是日期,如果返回的数据存在渲染出✨
,这里就是根据自己的情况而定,我们接着来
- 我给其中的一个
div
添加了点击事件@click="allcalendar(data)"
,将点击到的当天数据传过去,有关el-calendar
的自定义内容根据官网的说明提一句:
dateCell scoped slot 参数
date:格代表的日期
data:{ type, isSelected, day},
type
表示该日期的所属月份,可选值有prev-month
,current-month
,next-month
;isSelected
标明该日期是否被选中;day
是格式化的日期,格式为yyyy-MM-dd
关于点击事件:
// 选择日期,再获取对应日期的数据
allcalendar(data) {
this.productDate = data.day
this.haveDateInfo()
// 其他省略内容
},
其中this.haveDateInfo()
就是我们调用接口的地方,不过多介绍,我们收到传入的天数,这段代码看似来说没有如何问题,从点击事件获取到点击的日期,再赋值到data
的数据里面,在调用接口来对点击的日期进行添加修改等操作
- 但是问题却出现了:日历出现的时候获取数据和通过自定义内容将数据进行展示,到这里还没有问题,当鼠标点击切换到其他日期的时候,会有概率出现日期赋值不了,这样一来,我们就获取不到点击的日期当日的数据内容,也就不能通过接口获取我们要的数据内容
解决思路
出现这种问题,数组赋值不过去,可能会是异步问题,因为针对element-ui
里面的el-calendar
内容也没有如何事件,于是修改点击事件的代码,会不会是因为请求的问题导致的,并添加上加载动画:
async allcalendar(data) {
this.productDate = data.day
const loading = this.$loading({
lock: true,
text: 'Loading',
spinner: 'el-icon-loading',
background: 'rgba(0, 0, 0, 0.7)'
})
try {
await this.haveDateInfo()
} catch (error) {
console.log(error)
}
loading.close()
},
通过使用这种方法,问题依旧没有解决,加载动画和使用vue-devtools
来查看也是没有成功的,只有能看到记载动画才会被赋值
一筹莫展的时候,看到el-calendar
是可以使用v-model
可以绑定的,这样一来就可以检测到变化,于是修改代码,使用绑定加监听的方法
解决代码
完善代码部分:
对之前的内容稍作简化
<el-calendar v-model="calenderDate">
<div slot="dateCell" slot-scope="{data}">
<div :class="data.isSelected ? 'is-selected' : ''">
<div class="day">
{{ data.day.split('-').slice(1).join('-') }}
{{ data.isSelected ? '✔️' : '' }}
</div>
</div>
</div>
</el-calendar>
data
部分填入calenderDate:''
即可
watch:{
calenderDate(newVal, oldVal) {
// 格式化 因为绑定的数组不是我们想用的,这里以2022-22-22这种格式作为演示
this.calenderDate = this.formatDate(newVal)
// 这里就是我们处理数据,调用接口的位置
this.allcalendar()
}
}
async allcalendar() {
this.productDate = this.calenderDate
const loading = this.$loading({
lock: true, //加上这个 页面点击日历的时候会莫名其妙抖动一下 因为我界面上有滚动条,所以我注释了
text: 'Loading',
spinner: 'el-icon-loading',
background: 'rgba(0, 0, 0, 0.7)'
})
try {
// 这里调用接口肯定是需要点击的日期的,书写自己的处理逻辑即可
await this.haveDateInfo()
} catch (error) {
console.log(error)
}
loading.close()
},
有关这里使用的格式化也一并作为展示:
// 格式化日期函数
formatDate(date) {
const value = new Date(date)
const year = value.getFullYear()
const month = (value.getMonth() + 1).toString().padStart(2, '0')
const day = value.getDate().toString().padStart(2, '0')
return `${year}-${month}-${day}`
}