项目需要,需要一个日历表组件,产品狗嫌弃第三方提供的组件样式太丑,功能不全,带刀和产品理论奈何产品有枪。无奈只能自己写一个,发布完这条博客我就提离职,再也不和产品多BB。
Html=>
`<template>
<div class="calender"> <div class="calender-title-wrapper"> <div class="calender-title"> <div class="calender-arrow-item left2" v-if="false"></div> <div class="calender-arrow-item left1" @click="month--"></div> <div class="calender-Date-text">{{year}}年{{month}}月</div> <div class="calender-arrow-item right1" @click="month++"></div> <div class="calender-arrow-item right2" v-if="false"></div> </div> </div> <div class="calender-content-wrapper"> <div class="calender-days-wrapper"> <div class="calender-days">日</div> <div class="calender-days">一</div> <div class="calender-days">二</div> <div class="calender-days">三</div> <div class="calender-days">四</div> <div class="calender-days">五</div> <div class="calender-days">六</div> </div> <div class="calender-content"> <div class="calender-item-wrapper" v-for="item in daysArr" :class="{'no-current-day':item.month!=month, active:item === clickItemObj, currentDay:item.day===_CurrentDate.day&& item.month===_CurrentDate.month&& item.year===_CurrentDate.year}" @click="_clickDaysItem(item)" > <div class="calender-item">{{item.day}}</div> <div class="tem-wrapper"> <span class="temp" v-for="d in markArr" :style="{background: d.color}" v-if="_visibleTemp(d,item)"></span> </div> </div> </div> <div class="calender-mask-wrapper"> <div class="calender-mask-item" v-for="item in markArr"> <span class="tem" :style="{background:item.color}"></span> <span class="text">{{item.name}}</span> </div> </div> </div></div>
</template>`
js=>
<script> export default { name: "calender", props:{ markArr:{ type:Array, default(){ return [] } } }, data(){ return { day:'', month:'', year:'', currentDays:'', daysArr:[], clickItemObj:{} } }, mounted() { this._getCurrentDate() }, methods:{ //点击日期 _clickDaysItem(item){ //选中日期标记与解除标记 if(this.clickItemObj === item){ this.clickItemObj = {} }else { this.clickItemObj = item } //非当前月份跳转 if(item.month!=this.month){ this.month = item.month } //传入事件筛选回返 this._user_defined_events(item) }, //mark渲染 _user_defined_events(item){ for(let i=0;i<this.markArr.length;i++){ if(this.markArr[i].days.includes(`${item.year}-${item.month}-${item.day}`)){ this.$emit(this.markArr[i].clickEvent,item) } } }, //是否显示mark _visibleTemp(d,item){ let dateStr = `${item.year}-${item.month}-${item.day}` return d.days.includes(dateStr) }, //获取月份天数 _getDaysForMonth(year,month,type){ let temp=new Date(year,month,type); let day = new Date(temp.getTime() - 864e5).getDate(); this.currentDays = day this._getFirstDaysForMonth(this.year,this.month) }, //获取当前日期 _getCurrentDate(){ let date = new Date() this.day = date.getDate() this.month = date.getMonth()+1 this.year = date.getFullYear() this._getDaysForMonth(this.year,this.month,1) }, //获取切换页月份第一天是周几与最后一天并获取月前与月后填补数组 _getFirstDaysForMonth(year,month){ let weekdays = new Date(`${year}-${month}-01`).getDay() let beforeMonthDaysArr = [] let currentMonthDaysArr = [] let afterMonthDaysArr = [] //获取上一月总天数 if(month){ let temp=new Date(year,month-1,1); let day = new Date(temp.getTime() - 864e5).getDate(); for(let i=0;i<day;i++){ beforeMonthDaysArr.push({ year:year, month:month-1, day:i+1 }) } beforeMonthDaysArr.splice(0,beforeMonthDaysArr.length-weekdays) }else{ //12月 } //获取当前月总天数 let temp=new Date(year,month,1); let day = new Date(temp.getTime() - 864e5).getDate(); let afterWeekdays = new Date(`${year}-${month}-${day}`).getDay() for(let i=0;i<day;i++){ currentMonthDaysArr.push({ year:year, month:month, day:i+1 }) } if(beforeMonthDaysArr.length+currentMonthDaysArr.length+6-afterWeekdays===35){ for(let i=0;i<13-afterWeekdays;i++){ afterMonthDaysArr.push({ year:year, month:month+1, day:i+1 }) } }else{ for(let i=0;i<6-afterWeekdays;i++){ afterMonthDaysArr.push({ year:year, month:month+1, day:i+1 }) } } this.daysArr = [...beforeMonthDaysArr,...currentMonthDaysArr,...afterMonthDaysArr] //获取下一月总天数 } }, watch:{ 'month'(){ if(this.month===0){ this.month = 12 this.year-- } if(this.month===13){ this.month = 1 this.year++ } this._getDaysForMonth(this.year,this.month,1) } }, computed:{ _CurrentDate(){ let date = new Date() let {day,month ,year} = { day:date.getDate(), month:date.getMonth()+1, year:date.getFullYear() } return {day,month ,year} } } }</script>
css=>
tips:我用的css解析器是stylus,用less和sass之类的大佬麻烦动动你们的小手加个花括号
<style scoped lang="stylus"> .calender text-align center min-width 280px height 400px .calender-title-wrapper height 44px line-height 44px .calender-title display flex margin 0 auto width 280px .calender-arrow-item flex 0 0 40px cursor pointer &.left1 background url("icon_left.svg") no-repeat center &.left2 background url("icon_left2.svg") no-repeat center &.right1 background url("icon_right.svg") no-repeat center &.right2 background url("icon_right2.svg") no-repeat center .calender-Date-text flex 1 color #424242 font-size 16px .calender-content-wrapper .calender-days-wrapper display flex height 44px line-height 44px margin-bottom 11px .calender-days flex 1 color #A7A7A7 font-size 14px .calender-content .calender-item-wrapper position relative float left width 14.285% height 44px line-height 44px color #686868 cursor pointer .tem-wrapper position absolute left 50% height 10px width 40px transform translate3d(-50%,35px,0) font-size 0 .temp position relative display inline-block line-height 10px width 6px height 6px background #4fff41 border-radius 3px top -16px margin 0 2px .calender-item position absolute left calc(50% - 20px) top calc(50% - 20px) height 40px width 40px border-radius 20px line-height 40px &:hover background #FFC912 &.no-current-day color #DCDCDC &.currentDay color #ffffff .calender-item background #FFC912 &.active color #ffffff .calender-item background #FFC912 .calender-mask-wrapper height 37px .calender-mask-item height 37px line-height 37px width 25% float left .tem margin-right 3px display inline-block height 8px width 8px border-radius 4px .text font-size 12px</style>
给各位大佬呈上APP.vue中的调用,以及参数详细用法
App.vue中的@test1事件是在在入参markArr中定义的,其中在markArr中color是标记日期的样式颜色,name是显示的样式名称,days是日期数组,clickEvent就是自定义事件名称
<template> <div id="app"> <calender @test1="test" :markArr="[ { color:'#76ff19', name:'测试一', days:['2019-5-8','2019-5-11','2019-5-14','2019-5-22'], clickEvent:'test1' }, { color:'#ff1323', name:'测试二', days:['2019-5-9','2019-5-11','2019-5-3','2019-5-1'], clickEvent:'test2' }, { color:'#ffc518', name:'测试三', days:['2019-5-18','2019-5-11','2019-5-7','2019-5-4'], clickEvent:'test3' }, { color:'#ff26fc', name:'测试四', days:['2019-5-28','2019-5-11','2019-5-30','2019-5-31'], clickEvent:'test4' } ]" ></calender> <!--<backwards></backwards>--> </div></template><script> import calender from './components/calender/calender' import backwards from './components/backwards/backwards'export default { name: 'App', components:{ calender, // backwards }, methods:{ test(item){ console.log(item) } }}</script><style lang="stylus">#app position absolute height 100% width 100%</style>
丢个成果图
是不是很丑?我故意的,想要好看自己改去吧,大致功能全都实现了