1、当前组件说明
一个用vue实现的简单日历组件,可以手动设置日历的宽高,未设置时,有默认宽高,设置后,其中的每个日期项的宽高可以根据设定的宽高自适应、可以设置当前选中日期,可以设置时间可用范围,可以通过左右箭头进行日期切换。(第一次使用简书,代码格式比较丑,而且换行很高,也不知道怎么调整,大家见谅)
2、组件效果展示
3、组件实现代码
{{vdpYear+'年'+vdpMonth+'月'}}
{{item}}
:style="itemStyles"
v-for="(item,i)indateList":key="i"@click="toSelect(item)"
:class="(item.disabled===false&&item.actived?'actived':'grey')+(item.checked?'checked':'')+(item.today?'today':'')+(item.disabled?'disabled':'')">
{{item.day}}
exportdefault{
name:'cDatePicker',
props:{
//要求传入的值必须为yyyy-MM-dd格式数据
value:{
type:String
},
// 日历显示的宽度,默认300px
width:{
type:Number,
default:300
},
// 日历显示的高度,默认300px
height:{
type:Number,
default:300
},
// 日历工具栏的显示高度,默认32px
toolHeight:{
type:Number,
default:32
},
// 日历中每个时间项的行高
lineHeight:{
type:Number
},
margin:{
type:Number,
default:2
},
// 日历可选范围-开始时间
start:{
type:String,
default:''
},
// 日历可选范围-结束时间
end:{
type:String,
default:''
}
},
watch:{
//监听外部插入的value值变化
//value(n,l){
//this.init()
//}
},
data(){
return{
xqList:['日','一','二','三','四','五','六'],
vdpYear:0,//选择的年
vdpMonth:0,//选择的月
vdpDay:0,//选择的日
monthStart:0,//月初
monthEnd:0,//月末
monthWeek:0,
dateList:[]//当前时间集合
}
},
methods:{
//初始化
init(){
constnow=this.newDate(this.value||undefined)
this.vdpYear=now.getFullYear()
this.vdpMonth=now.getMonth()+1
this.vdpDay=this.value?now.getDate():0
putePicker()
},
//选中某一天
toSelect(item){
if(item&&item.disabled===false){
////通过重新生成dateList数据达到改变选中效果
//this.vdpDay=item.day
//putePicker()
//通过直接循环修改dateList数据达到改变选中效果
this.dateList=this.dateList.map(v=>{
v.checked=false
returnv
})
this.vdpDay=item.day
item.checked=true
this.$emit('input',item.date)
this.$emit('on-change',item.date,this.newDate(item.date))
}
},
//上一个月
toVdpUpper(){
if(this.vdpMonth>1){
this.vdpMonth--
}else{
this.vdpYear--
this.vdpMonth=12
}
this.vdpDay=0
putePicker()
},
//下一个月
toVdpLower(){
if(this.vdpMonth
this.vdpMonth++
}else{
this.vdpYear++
this.vdpMonth=1
}
this.vdpDay=0
putePicker()
},
//计算月初、月末、月初是星期几及当前日期数据
computePicker(){
constyc=newDate(this.vdpYear,this.vdpMonth-1,1)//月初
constym=newDate(this.vdpYear,this.vdpMonth,0)//月末
this.monthStart=yc.getDate()
this.monthEnd=ym.getDate()
this.monthWeek=yc.getDay()
constv=[]
for(leti=0;i
v.push(this.getVdpDay(i,'-'))
}
this.dateList=v
},
//获取当前日期核心方法
getVdpDay(index,defV){
let_disabled=false
let_actived=false
let_year=this.vdpYear
let_month=this.vdpMonth
let_day=0
if(this.monthWeek===0){
index=index-7
}
if(index
//计算上月
_month--
if(_month===0){
_year--
_month=12
}
_day=newDate(_year,_month,0).getDate()-this.monthWeek+index+1//算当前选中月的上一月月末
}elseif(index>(this.monthWeek+this.monthEnd-1)){
//计算下月
_month++
if(_month===13){
_year++
_month=1
}
_day=newDate(this.vdpYear,this.vdpMonth,1).getDate()+index-(this.monthEnd+this.monthWeek)//算当前选中月的下一月月初
}else{
//计算当月
_day=this.monthStart+index-this.monthWeek
_actived=true
}
//计算开始日期和结束日期
if(this.start||this.end){
const_curtm=newDate(_year+'/'+_month+'/'+_day)
if(this.start){
const_start=this.newDate(this.start)
if(_curtm
_disabled=true
}
}
if(this.end){
const_end=this.newDate(this.end)
if(_curtm>_end){
_disabled=true
}
}
}
return{year:_year,month:_month,day:_day,date:this.generateDateStr(_year,_month,_day),checked:this.verifyCheckDate(_year,_month,_day),actived:_actived,today:this.isToday(_year,_month,_day),disabled:_disabled}//_disabled?(defV||''):_day
},
//生成时间字符串
generateDateStr(year,month,day){
returnyear+'-'+(month>9?month:'0'+month)+'-'+(day>9?day:'0'+day)
},
//验证是否是当前选中的日期
verifyCheckDate(year,month,day){
if((this.value&&this.value===this.generateDateStr(year,month,day))||(this.vdpYear===year&&this.vdpMonth===month&&this.vdpDay===day)){
returntrue
}else{
returnfalse
}
},
//验证是否今天
isToday(year,month,day){
if(this.generateDateStr(year,month,day)===this.formatDate(newDate(),'yyyy-MM-dd')){
returntrue
}else{
returnfalse
}
},
//字符串转换Date解决ie11时间兼容性问题
newDate(time,defV){
letv=defV===undefined?newDate():defV
if(time){
v=newDate(time.replace(/-/g,'/'))
}
returnv
},
//时间格式化兼容IE
formatDate(date,format){
if(date){
vartime
if(typeofdate==='string'){
time=newDate(date.replace(/-/g,'/'))
}elseif(typeofdate==='object'){
time=newDate(date)
}
varo={
'M+':time.getMonth()+1,//月份
'd+':time.getDate(),//日
'h+':time.getHours(),//小时
'm+':time.getMinutes(),//分
's+':time.getSeconds(),//秒
'q+':Math.floor((time.getMonth()+3)/3),//季度
S:time.getMilliseconds()//毫秒
}
if(/(y+)/.test(format))format=format.replace(RegExp.$1,(time.getFullYear()+'').substr(4-RegExp.$1.length))
for(varkino){if(newRegExp('('+k+')').test(format))format=format.replace(RegExp.$1,(RegExp.$1.length===1)?(o[k]):(('00'+o[k]).substr((''+o[k]).length)))}
returnformat
}else{return''}
}
},
computed:{
itemStyles(){
const_w=(this.width/7-this.margin*2)
const_h=((this.height-this.toolHeight)/7-this.margin*2)
const_lh=this.lineHeight?this.lineHeight:(_h-1)+'px'//parseInt(_h)
return{width:_w+'px',height:_h+'px',margin:this.margin+'px','line-height':_lh}
}
},
created(){
this.init()
}
}
.picker-box{
width:100%;
height:100%;
margin:0auto;
font-size:14px;
}
.picker-box.picker-tool{
height:50px;
line-height:50px;
text-align:center;
}
.picker-box.picker-body{
width:100%;
}
.picker-box.picker-body.picker-item,.picker-box.picker-body.picker-title{
width:calc(14.285714285%-10px);
height:calc(16.666666666%-10px);
line-height:2.6;
text-align:center;
border:1pxsolid#ececec;
border-radius:5px;
margin:5px;
float:left;
}
.picker-box.picker-body.picker-item{
cursor:pointer;
}
.picker-box.picker-body.picker-title{
background:#eaf0f5;
}
.picker-box.picker-body.grey{
color:#b2b2b2;
border:1pxsolid#ececec;
background:#fbfbfb;
}
.picker-box.picker-body.actived{
color:#3c3c3c;
border:1pxsolid#ececec;
}
.picker-box.picker-body.today{
background:#d8f9d8;
border:1pxsolid#ececec;
}
.picker-box.picker-body.checked{
color:#fff;
background:#19be6b;
border:1pxsolid#19be6b;
}
.picker-box.picker-body.disabled{
color:#b2b2b2;
background:#f2f2f2;
border:1pxsolid#ececec;
cursor:not-allowed;
}
4、组件调用示例
importcDatePickerfrom'./cDatePicker'
exportdefault{
components:{
cDatePicker
},
data(){
return{
timeText:'-07-16',
start:'-06-12',
end:'-08-05'
}
}
}
5、尚需待完善
a、点击年,进行年份切换
b、点击月,进行月份切换。