需求描述:
日历组件,某些日期被人选了,就不能再选,用一个颜色标记。用户可以选择部分能选的。
类似这样的需求图片。
办法1是,vant-ui 微信小程序插件 本身的日期组件是可以实现的。
具体方法:
<van-calendar
title="日历"
:show="true"
:formatter="formatter1"
color="#07c160"
type="range"
:show-confirm="false"
/>
我们可以通过`formatter`来自定义渲染内容。
formatter1(day){
// 周日全天不可选
let week = day.date.getDay()
if(week == 0){
day.type = 'disabled_yes' // 很牛笔 很关键
}
const month = day.date.getMonth() + 1;
const date = day.date.getDate();
if (month === 5) {
if (date === 1) {
day.topInfo = '劳动节';
} else if (date === 4) {
day.topInfo = '五四青年节';
} else if (date === 11) {
day.text = '今天';
}
}
if (day.type === 'start') {
day.bottomInfo = '入住';
} else if (day.type === 'end') {
day.bottomInfo = '离店';
}
return day
},
重点: 通过formate函数,我们可以指定日期day.type的类型为disabled
那么,禁用的样式就是官方自己的默认的日期禁用样式。
但是我们需要自定义禁用样式, 那么 day.type = 'day–disabled_yes’设置为一个自定义的名称, vant的组件会自动生成一个 van-calendar__day--disabled_yes
的类名,然后 我们通过这个类名 自己写样式就行了。
<style>
.van-calendar__day--disabled_yes {
color: red;
}
</style>
最后的效果就是这样子
但是这种方法有个坑,formate函数,只会在当月执行,其他月份,需要点击月份才能触发,并且担心性能问题。 没有继续研究下去。
方法二:使用wx_calendar这个改写
源码地址:https://github.com/treadpit/wx_calendar
源码文档:https://treadpit.github.io/wx_calendar/v1/guide.html#%E5%BF%AB%E9%80%9F%E6%8E%A5%E5%85%A5
注意: 他有v1 和v2两个版本,方式不一样。 我使用的是v1版本
将src/component/calendar这个目录下的文件全部拷贝到自己的组件目录。
我的是wepy2框架 都可以直接拷贝,原生小程序当然也可以直接用。
文档可以传入我们需要禁用的日期
使用示例demo
<template>
<div class="container-wrap">
<calendar calendarConfig="{{calendarConfig}}" />
</div>
</template>
import wepy from '@wepy/core'
import store from '@/store'
import { disableDay } from '../components/calendar/main.js'
wepy.page({
store,
data: {
calendarConfig: {
multi: true,
disableMode: { // 禁用某一天之前/之后的所有日期
type: 'before' // [‘before’, 'after']
// date: '2020-03-24', // 无该属性或该属性值为假,则默认为当天
},
onlyShowCurrentMonth: false
// defaultDay: '2018-3-6'
}
},
computed: {
},
watch: {
},
methods: {
initData() {
// jump(2018, 6, 6)
disableDay([
{
year: 2021,
month: '06',
day: '08',
class: 'lock'
},
{
year: 2021,
month: '06',
day: '27',
class: 'lock'
}
])
}
},
onLoad() {
console.log('load')
},
onShow() {
console.log('show')
},
onReady() {
this.initData()
},
onHide() {
}
})
</script>
<config>
{
navigationBarTitleText: 'demo',
usingComponents: {
"calendar": "../components/calendar/index",
'noData':'../components/noData'
}
}
</config>
我们传入给组件的禁用日期数据多写了一个class:'lock'
属性,
我们再需要改写一下组件的源码:
calendar/func/day.js
/**
* 禁用指定日期
* @param {array} dates 禁用
*/
disableDays(dates) {
const { disableDays = [], days } = this.getData('calendar')
if (Object.prototype.toString.call(dates) !== '[object Array]') {
return logger.warn('disableDays 参数为数组')
}
let _disableDays = []
if (dates.length) {
_disableDays = uniqueArrayByDate(dates.concat(disableDays))
const disableDaysCol = _disableDays.map(d => getDate.toTimeStr(d))
// console.log('disableDaysCol', disableDaysCol)
// console.log('days', days)
days.forEach(item => {
const cur = getDate.toTimeStr(item)
// if (disableDaysCol.includes(cur)) item.disable = true // 原来的逻辑
// ++++++ 新增逻辑 sart +++++++
disableDaysCol.forEach((v, i) => {
if (cur === v) {
item.disable = true
item.class = _disableDays[i].class ? _disableDays[i].class : ''
}
})
// ++++++ 新增逻辑 end +++++++
})
} else {
days.forEach(item => {
item.disable = false
})
}
this.setData({
'calendar.days': days,
'calendar.disableDays': _disableDays
})
}
我们把我们想出入的类名就传进去了。并且,会把这个类型渲染到日期上面。
然后我们添加这个自定义样式:
.default_date-disable.lock {
background-color: red;
}
calendar/func/runder.js
/**
* 设置日历面板数据
* @param {number} year 年份
* @param {number} month 月份
* @param {number} curDate 日期
* @param {boolean} disableSelect 是否禁用选中
*/
calculateDays(year, month, curDate, disableSelect) {
return new Promise(resolve => {
// 避免切换日期时样式残影
this.resetDates()
let days = []
const {
disableDays = [],
chooseAreaTimestamp = [],
selectedDay: selectedDates = []
} = this.getData('calendar')
days = Day(this.Component).buildDate(year, month)
let selectedDay = selectedDates
if (!disableSelect) {
selectedDay = this.setSelectedDay(year, month, curDate)
}
const selectedDayStr = selectedDay.map(d => getDate.toTimeStr(d))
const disableDaysStr = disableDays.map(d => getDate.toTimeStr(d))
console.log('disableDaysStr', disableDaysStr)
const [areaStart, areaEnd] = chooseAreaTimestamp
days.forEach(item => {
const cur = getDate.toTimeStr(item)
const timestamp = getDateTimeStamp(item)
if (selectedDayStr.includes(cur) && !disableSelect) {
item.choosed = true
if (timestamp > areaEnd || timestamp < areaStart) {
const idx = selectedDay.findIndex(
selectedDate =>
getDate.toTimeStr(selectedDate) === getDate.toTimeStr(item)
)
selectedDay.splice(idx, 1)
}
} else if (
areaStart &&
areaEnd &&
timestamp >= areaStart &&
timestamp <= areaEnd &&
!disableSelect
) {
item.choosed = true
selectedDay.push(item)
}
// if (disableDaysStr.includes(cur)) item.disable = true // 原来的逻辑
// ++++++ 新增逻辑 sart +++++++
disableDaysStr.forEach((v, i) => {
if (cur === v) {
item.disable = true
item.class = disableDays[i].class ? disableDays[i].class : ''
}
})
// ++++++ 新增逻辑 end +++++++
const {
disableDateTimestamp,
disableType
} = this.__getDisableDateTimestamp()
let disabelByConfig = false
if (disableDateTimestamp) {
if (
(disableType === 'before' && timestamp < disableDateTimestamp) ||
(disableType === 'after' && timestamp > disableDateTimestamp)
) {
disabelByConfig = true
}
}
const isDisable = disabelByConfig || this.__isDisable(timestamp)
if (isDisable) {
item.disable = true
item.choosed = false
}
})
this.setData(
{
'calendar.days': days,
'calendar.selectedDay': [...selectedDay] || []
},
() => {
resolve()
}
)
})
}
最终的显示效果如下:
红色就是我们传入的需要禁用的。灰色背景的,就是插件默认的禁用样式。
整个组件的样式都是可以自定义修改的,具体就查看组件内的样式文件。
使用calendar v2版本实现以上需求
第一步:把源码src/component/v2目录下的文件全部拷贝到自己的组件文件夹下,我的是src/components/calendar2
第二步:安装官方文档说的开干
<style lang="less">
.default_date-disable.lock {
background-color: red;
}
// 自定义样式
.orange-date {
background-color: rgb(248, 238, 147);
}
</style>
<template>
<div class="container-wrap">
<p>日历插件1</p>
<calendar calendarConfig="{{calendarConfig}}" />
<p>日历插件2</p>
<calendar2 id="calendar" config="{{calendarConfig2}}" />
</div>
</template>
<script>
import wepy from '@wepy/core'
import store from '@/store'
import { disableDay } from '../components/calendar/main.js'
import plugin from '../components/calendar2/plugins/index.js'
import selectable from '../components/calendar2/plugins/selectable.js'
plugin.use(selectable) // 安装日期组件的插件
wepy.page({
store,
data: {
calendarConfig: {
multi: true,
disableMode: { // 禁用某一天之前/之后的所有日期
type: 'before' // [‘before’, 'after']
// date: '2020-03-24', // 无该属性或该属性值为假,则默认为当天
},
onlyShowCurrentMonth: false
// defaultDay: '2018-3-6'
},
calendarConfig2: {
multi: true,
// theme: 'elegant',
// hideHeader: true,
emphasisWeek: false,
chooseAreaMode: false,
disableMode: { // 禁用某一天之前/之后的所有日期
type: 'before' // [‘before’, 'after']
}
}
},
computed: {
},
watch: {
},
created() {
console.log('created')
// const calendar = this.$app.selectComponent('#calendar').calendar
// console.log('calendar', calendar)
},
mounted() {
console.log('mounted')
},
methods: {
initData() {
// const pages = getCurrentPages()
// const currentPage = pages[pages.length - 1]
// console.log('this.calendar', currentPage)
// console.log('this.calendar', jump)
// jump(2018, 6, 6)
disableDay([
{
year: 2021,
month: '06',
day: '08',
lock: true,
class: 'lock'
},
{
year: 2021,
month: '06',
day: '27',
lock: true,
class: 'lock'
}
])
}
},
onPullDownRefresh: function () {
// 调用刷新时将执行的方法
console.log('下拉刷新')
},
onReachBottom() {
// console.log('上拉加载')
},
onPageScroll: function(e) {
},
onLoad() {
console.log('load')
},
onShow() {
console.log('show')
},
onReady() {
console.log('ready')
this.initData()
const toSet = [
{
year: 2021,
month: 7,
date: 15
},
{
year: 2021,
month: 7,
date: 18
}
]
const calendar = this.$wx.selectComponent('#calendar').calendar
calendar.setSelectedDates(toSet)
const toDis = [
{
year: 2021,
month: 7,
date: 12,
class: 'orange-date'
},
{
year: 2021,
month: 7,
date: 13,
class: 'orange-date'
},
{
year: 2021,
month: 7,
date: 14,
class: 'orange-date'
}
]
// 设置禁用日期
calendar.disableDates(['2021-7-12', '2021-7-13', '2021-7-14'])
// 设置自定义日期样式
calendar.setDateStyle(toDis)
// calendar.jump({year: 2018, month: 6, date: 6})
},
onHide() {
}
})
</script>
<config>
{
navigationBarTitleText: 'demo',
usingComponents: {
"calendar": "../components/calendar/index",
"calendar2": "../components/calendar2/index",
}
}
</config>
v2版本的,我们就不需要手动去改源码了。因为,v2版本插件,提供了一个设置指定日期样式的方法calendar.setDateStyle(toSet)
所以,我们可以传入自定义的样式类名进去就行了。
注意:v2版本 官方有问题,有bug ,走不通。 最后方案还是用的v1实现的。