時間日曆控件不管在Pc端仍是移動端,都是十分重要且有用的一個組件,最近重拾了本身的UI庫,按照ElementUI
的組件種類,以Pc端爲核心進行組件開發【 適配Vue + Less 】,目前項目已有近20個組件,若是你們有興趣,歡迎來GIT上踩踩哦vue
附上GIt地址 - github.com/Jason9708/C…git
本文帶來的日曆控件與以往的日曆控件不太相同,我將以Window自帶的日曆做爲大概的UI設計,摸出一個可拖拽的浮窗型日曆控件github
效果以下:web
index.js
:工具函數文件index.less
:樣式表index.vue
:組件文件calendar.vue
:測試組件文件index.js
工具函數// 定義月份英文縮寫
const englishMonthList = [
'Jan',
'Feb',
'Mar',
'Apr',
'May',
'Jun',
'Jul',
'Aug',
'Sept',
'Oct',
'Nov',
'Dec'
]
// 根據傳入日期獲取指定年月日時分秒
const getNewDate = (date) => {
let year = date.getFullYear()
let month = date.getMonth()
let day = date.getDate()
let hour = date.getHours()
let minute = date.getMinutes()
let second = date.getSeconds()
return { year, month, day, hour, minute, second }
}
// 獲取指定年月日獲取日期
const getDate = (year, month, day) => {
return new Date(year, month, day);
}
// 獲取當前月的英文拼寫
const englishMonth = (month) => {
let engMonth = englishMonthList[month]
return engMonth
}
// 導出函數
export {
getNewDate,
getDate,
englishMonth
}
複製代碼
index.vue
組件文件<template>
<div class='cai-calendar-wrapper' id='cai-calendar-wrapper'>
<!-- 頭部,即未展開的組件 -->
<div class='cai-calendar-header'>
<div class='cai-calendar-header-time'>{{currentTime.hour}}:{{formatDate(currentTime.minute)}}:{{formatDate(currentTime.second)}}</div>
<div class='cai-calendar-header-date'>
{{currentTime.year}}年{{currentTime.month + 1}}月{{currentTime.day}}日
</div>
</div>
<!-- 日曆容器 transition實現動畫效果-->
<transition name='calendar'>
<div class='cai-calendar-container' v-if='showCalendar'>
<!-- 容器頭部,實現上下月切換,以及返回今天 -->
<div class='container-header'>
<span class='container-header-date'>
{{choosenMonthDec}}
</span>
<i class='cai-icon-up' @click='handlePrevMonth'></i>
<i class='cai-icon-down' @click='handleNextMonth'></i>
<span class='container-header-today' @click='handleToday'>今天</span>
</div>
<!-- 列表頭行,顯示週一到週日 -->
<div class="calendar-week">
<div v-for="(item, index) in calendarTitleArr" :key="index" class="week-item">{{item}}</div>
</div>
<!-- 列表 排列每個日期 -->
<div class="calendar-week">
<div v-for="(item, index) in calendarList" :key="index" class="week-item date-item" :class='[{today:isCurrentDay(item.date)}]' @click='chooseDate(item)'>
<span>{{item.day}}</span>
</div>
</div>
</div>
</transition>
<!-- 自定義彈窗 transition實現動畫效果 -->
<transition name='calendar-dialog'>
<div class='cai-calendar-dialog' v-if='showCalendarDialog'>
<i class='cai-icon-close' @click='showCalendarDialog = false'></i>
<!-- 具名插槽實現用戶自定義內容 -->
<slot name="content">
</slot>
</div>
</transition>
</div>
</template>
<script>
import * as utils from './index.js';
export default {
name:'CaiCalendar',
data(){
return{
currentTime:{ // 當前時間年月日,時分秒,用於頭部顯示實時時間
year:'',
month:'',
day:'',
hour:'',
second:''
},
calendarTitleArr: [ // 星期英文拼寫
'MON',
'TUE',
'WED',
'THU',
'FRI',
'SAT',
'SUN '
],
calendarList: [], // 日曆數組
choosenMonthDec:'', // 日曆容器頭部的可選月份描述
choosenMonth:'', // 日曆容器頭部的可選月份
interval:'', // 存儲定時器
showCalendar:false, // 是否顯式完整日曆
showCalendarDialog:false, // 是否顯示自定義彈窗
}
},
mounted(){
// 拖拽
this.drag()
// 第一次不延時
this.handleNowDate()
this.interval = setInterval( () => {
this.handleNowDate()
}, 1000)
},
methods:{
// 拖拽函數
drag(){
var that = this
var drag = document.getElementById('cai-calendar-wrapper')
// //點擊某物體時,用drag對象便可,move和up是全局區域,
// 也就是整個文檔通用,應該使用document對象而不是drag對象(不然,採用drag對象時物體只能往右方或下方移動)
drag.onmousedown = function(event){
var event = event || window.event //兼容IE瀏覽器
// 鼠標點擊物體那一刻相對於物體左側邊框的距離=點擊時的位置相對於瀏覽器最左邊的距離-物體左邊框相對於瀏覽器最左邊的距離
var diffX = event.clientX - drag.offsetLeft
var diffY = event.clientY - drag.offsetTop
var startX = event.clientX
var startY = event.clientY
if(typeof drag.setCapture !== 'undefined'){
drag.setCapture()
}
// 鼠標移動,修改定位
document.onmousemove = function(event){
var event = event || window.event
var moveX = event.clientX - diffX
var moveY = event.clientY - diffY
if(moveX < 0){
moveX = 0
}else if(moveX > window.innerWidth - drag.offsetWidth){
moveX = window.innerWidth - drag.offsetWidth
console.log(moveX)
}
if(moveY < 0){
moveY = 0
}else if(moveY > window.innerHeight - drag.offsetHeight){
moveY = window.innerHeight - drag.offsetHeight
}
drag.style.left = moveX + 'px'
drag.style.top = moveY + 'px'
}
document.onmouseup = function(event){
var targetClass = event.target.className
var event = event || window.event
var endX = event.clientX
var endY = event.clientY
if(startX === endX && startY === endY){
if(targetClass === 'cai-calendar-header' || targetClass === 'cai-calendar-header-time' || targetClass === 'cai-calendar-header-date')
that.turnCalendar()
}
console.log(this) // #document
this.onmousemove = null
this.onmouseup = null
// 適配低版本 ie
if(typeof drag.releaseCapture!='undefined'){
drag.releaseCapture()
}
}
}
},
// 切換完整日曆
turnCalendar(){
this.visibleCalendar(this.currentTime.year,this.currentTime.month)
this.showCalendar = !this.showCalendar
this.showCalendarDialog = false
},
// 是不是今天
isCurrentDay (date) {
let {year: currentYear, month: currentMonth, day: currentDay} = utils.getNewDate(new Date())
let {year, month, day} = utils.getNewDate(date)
return currentYear == year && currentMonth == month && currentDay == day
},
// 點擊上一個月
handlePrevMonth () {
let prevMonth = utils.getDate(this.choosenMonth.year,this.choosenMonth.month,1)
prevMonth.setMonth(prevMonth.getMonth() - 1)
this.choosenMonth.year = utils.getNewDate(prevMonth).year
this.choosenMonth.month = utils.getNewDate(prevMonth).month
this.visibleCalendar(this.choosenMonth.year,this.choosenMonth.month)
this.$emit('handlePrevMonth',this.choosenMonth.year,this.choosenMonth.month) // 傳給父組件,上個年和月份做爲傳遞數據
},
// 點擊下一個月
handleNextMonth () {
let nextMonth = utils.getDate(this.choosenMonth.year,this.choosenMonth.month,1)
nextMonth.setMonth(nextMonth.getMonth() + 1)
this.choosenMonth.year = utils.getNewDate(nextMonth).year
this.choosenMonth.month = utils.getNewDate(nextMonth).month
this.visibleCalendar(this.choosenMonth.year,this.choosenMonth.month)
this.$emit('handleNextMonth',this.choosenMonth.year,this.choosenMonth.month) // 傳給父組件,上個年和月份做爲傳遞數據
},
// 點擊回到今天
handleToday () {
this.choosenMonth.year = utils.getNewDate(new Date()).year
this.choosenMonth.month = utils.getNewDate(new Date()).month
this.visibleCalendar(this.choosenMonth.year,this.choosenMonth.month)
this.$emit('handleToday',this.choosenMonth.year,this.choosenMonth.month) // 傳給父組件,上個年和月份做爲傳遞數據
},
// 點擊日期
chooseDate(item){
this.showCalendarDialog = true
this.$emit('handleClickDay', item);
},
// 加載日曆
visibleCalendar(YEAR,MONTH){
let calendatArr = []
// 獲取指定時間年月日
let {year, month, day} = utils.getNewDate(utils.getDate(YEAR, MONTH, 1))
// 獲取指定月第一天星期幾
let currentFirstDay = utils.getDate(year, month, 1)
let weekDay = currentFirstDay.getDay()
console.log('weekDay',weekDay)
// 計算開始時間
let startTime = currentFirstDay - (weekDay - 1) * 24 * 60 * 60 * 1000
console.log('startTime',startTime)
// 獲取當前月份中日曆顯示幾天 ( 第一天是周5或周6,則顯示6行,不然顯示5行)
let monthDayNum
if (weekDay == 5 || weekDay == 6){
monthDayNum = 42
}else {
monthDayNum = 35
}
// 從第一天開始計算,每進行一次循環,日期加一天
for (let i = 0; i < monthDayNum; i++) {
calendatArr.push({
date: new Date(startTime + i * 24 * 60 * 60 * 1000),
year: year,
month: month + 1,
day: new Date(startTime + i * 24 * 60 * 60 * 1000).getDate(),
clickDay: false,
})
}
// 賦值日曆列表
this.calendarList = calendatArr
this.choosenMonth = {
year:year,
month:month
}
this.choosenMonthDec = `${utils.englishMonth(month)} ${year}` // 日曆容器頭部的可選月份
},
// 獲取當前時間,並賦值currentTime
handleNowDate(){
let {year, month, day, hour, minute, second} = utils.getNewDate(new Date())
this.currentTime = {year, month, day, hour, minute, second}
},
// 格式化日期 我的很多天期以 0X 的格式顯示
formatDate(date){
date = Number(date)
return date < 10 ? `0${date}` : date
}
},
destroyed(){
// 清除定時器
clearInterval('interval')
}
}
</script>
<style lang="less" scoped>
@import './index.less'; // 加入樣式表
@import '../../CaiIcon/component/index.less'; // 圖標樣式表(可無論)
</style>
複製代碼
關於以上代碼,須要注意如下:數組
Interval
,在調用前,必須手動調用一次,避免第一次也延時致使效果不佳index.less
:樣式表.cai-calendar-wrapper{
width:540px;
display: flex;
flex-direction: column;
align-items: center;
position: fixed;
user-select:none;
.cai-calendar-header{
width:100%;
display: flex;
flex-direction: column;
justify-content:center;
padding:20px;
background:rgba(9,9,9,0.8);
position:relative;
&:before{
content:'';
position: absolute;
top:0px;
left:0px;
height:100%;
width:5px;
background: #0097e6;
}
.cai-calendar-header-time{
text-align: left;
font-size:30px;
font-weight: 500;
color: #74b9ff;
margin-left:20px;
margin-bottom:10px;
}
.cai-calendar-header-date{
text-align: left;
font-size:15px;
color: #fff;
margin-left:30px;
}
}
.cai-calendar-container{
width:100%;
margin-top:5px;
opacity: 1;
padding:20px;
background:rgba(9,9,9,0.8);
transform-origin:top;
transform:rotateX(0deg);
display:flex;
flex-direction: column;
.container-header{
display: flex;
justify-content: flex-end;
align-items: center;
color:#fff;
margin-bottom:10px;
.container-header-date{
margin-right:10px;
}
.container-header-today{
margin:0px 10px;
padding:5px 10px;
color: #74b9ff;
font-size:12px;
border:1px solid #74b9ff;
border-radius:5px;
cursor:pointer;
transition: all .2s linear;
}
.container-header-today:hover{
color:#0984e3;
border-color:#0984e3;
}
.cai-icon-up {
margin-right:10px;
cursor:pointer;
transition:all .2s linear;
}
.cai-icon-down {
cursor:pointer;
transition:all .2s linear;
}
.cai-icon-up:hover {
color:#0984e3;
}
.cai-icon-down:hover {
color:#0984e3;
}
}
.calendar-week{
width: 100%;
display: flex;
flex-wrap: wrap;
border-right: none;
list-style: none;
margin: 0;
padding: 0;
.week-item{
width: 57px;
text-align: center;
font-size: 16px;
color: #fff;
font-weight: 600;
padding:0px;
margin:10px;
}
.date-item{
cursor:pointer;
transition:all .2s linear;
position: relative;
}
.date-item:hover{
color:#0984e3;
}
.today{
color:#74b9ff;
}
}
}
.cai-calendar-dialog{
position: absolute;
top:0px;
bottom:0px;
left:-330px;
width:300px;
background:rgba(9,9,9,0.8);
color:#fff;
overflow: auto;
.cai-icon-close{
position: absolute;
top:5px;
right:5px;
color:#fff;
cursor: pointer;
transition: all .2s linear;
}
.cai-icon-close:hover{
color:#0097e6;
}
}
// 關於彈窗的滾動條樣式覆蓋
.cai-calendar-dialog::-webkit-scrollbar {
width: 5px;
margin:2px;
height: 5px;
}
.cai-calendar-dialog::-webkit-scrollbar-button {
display: none;
}
.cai-calendar-dialog::-webkit-scrollbar-track {
background-color: transparent;
}
.cai-calendar-dialog::-webkit-scrollbar-thumb {
width: 3px;
background-color: #0097e6;
-webkit-border-radius: 3em;
-moz-border-radius: 3em;
border-radius: 3em;
}
// 日曆 - 進入/離開 動畫
.calendar-enter-active, .calendar-leave-active {
transition: all 1s
}
.calendar-enter, .calendar-leave-active {
transform:rotateX(-90deg);
opacity:0;
}
// 日曆彈窗 - 進入/離開 動畫
.calendar-dialog-enter-active, .calendar-dialog-leave-active {
transition: all 1s
}
.calendar-dialog-enter, .calendar-dialog-leave-active {
transform:translateX(30px);
opacity:0;
}
}
複製代碼
calendar.vue
:測試組件文件開源地址瀏覽器
該開源git是一個開源UI庫項目,目前開發近20款適配Vue
的UI組件,有興趣的小夥伴給點⭐app
部分組件截圖less