已解决
vue 自己捣鼓周日程日历组件
来自网友在路上 195895提问 提问时间:2023-11-02 15:26:03阅读次数: 95
最佳答案 问答题库958位专家为你答疑解惑
需求:想要一个周日程表,记录每天的计划,点击可查看详情。可自定义时间段通过后台获取时间段显示
分析:
通过需求,超级课程表app这款软件其中课表和这个需求很像,只不过这个需求第一列的时间段是自定义的,不是上午下午两个,但是原理都差不多
原本想找一些第三方插件使用,由于时间充足,而且自己也想封装成一个组件方便以后或许会碰到类似的需求,于是自己手动写了一个日程日历。
效果如下
优化修改:数据量大时,格子显示太长问题,这里进行了优化,如果超过2个就进行展开与收缩操作
例子
<template><div id="app"><WSchedule :planList="timePeriodList" :isFirstDayOfMondayOrSunday="7" :hasNumExpend="2" @handleDetail="handleDetail" @handleCardDetail="handleCardDetail" @changeWeek="changeWeek"><template v-slot:thing="{row}"><span>时段:{{ row.timePeriod }}</span><span>课程:{{ row.course }}</span><span>值班员:{{ row.watchman }}</span><span>地点:{{ row.place }}</span></template></WSchedule></div>
</template><script>import WSchedule from '@/components/WeekSchedule'export default {name: 'App',components: {WSchedule,},data() {/*** 获取当天时间* @returns {string}*/function getCurDay(num = 0) {var datetime = new Date();var year = datetime.getFullYear();var month = datetime.getMonth() + 1 < 10 ? "0" + (datetime.getMonth() + 1) : datetime.getMonth() + 1;let day = datetime.getDate()if ((day + num) > 0) {day = (day + num) < 10 ? "0" + (datetime.getDate() + num) : datetime.getDate() + num;} else {day = (day - num) < 10 ? "0" + (datetime.getDate() - num) : datetime.getDate() - num;}return `${year}-${month}-${day}`}return {timePeriodList: [{timePeriod: '8:00~10:00',schedule: [{isExpend: false,[getCurDay()]: [{timePeriod: '8:00~10:00',date: getCurDay(),course: '大学英语',watchman: '井底的蜗牛',place: '测试地点',status: 1,},{timePeriod: '8:00~10:00',date: getCurDay(),course: '大学英语',watchman: '井底的蜗牛',place: '测试地点',status: 2,},{timePeriod: '8:00~10:00',date: getCurDay(),course: '大学英语',watchman: '井底的蜗牛',place: '测试地点',status: 3,},],},{isExpend: false,[getCurDay(-1)]: [{id: 1,timePeriod: '8:00~10:00',date: getCurDay(-1),course: '大学英语',watchman: '井底的蜗牛',place: '测试地点',status: 1,},]}]},{timePeriod: '12:00~14:00',schedule: [{isExpend: false,[getCurDay()]: [{timePeriod: '12:00~14:00',date: getCurDay(),course: '大学英语',watchman: '井底的蜗牛',place: '测试地点',status: 2,},{timePeriod: '12:00~14:00',date: getCurDay(),course: '大学英语',watchman: '井底的蜗牛',place: '测试地点',status: 3,},],},{isExpend: false,[getCurDay(-1)]: [{timePeriod: '12:00~14:00',date: getCurDay(-1),course: '大学英语',watchman: '井底的蜗牛',place: '测试地点',status: 1,},{timePeriod: '实验室1',date: getCurDay(-1),course: '大学英语',watchman: '井底的蜗牛',place: '测试地点',status: 1,},{timePeriod: '实验室1',date: getCurDay(-1),course: '大学英语',watchman: '井底的蜗牛',place: '测试地点',status: 1,},]}]},{timePeriod: '14:00~16:00',schedule: []},],}},methods: {/*** 点击详情* @param row*/handleDetail(row){console.log(row)},/*** 点击卡片查看全部内容*/handleCardDetail(row) {console.log(row)},/*** 切换周* @param date*/changeWeek(date){console.log(date)}},
}
</script><style>
#app {font-family: Avenir, Helvetica, Arial, sans-serif;-webkit-font-smoothing: antialiased;-moz-osx-font-smoothing: grayscale;text-align: center;color: #2c3e50;margin-top: 60px;
}
</style>
封装组件 weekTools WeekSchedule/index.vue
<template><div class="course-week"><div class="week-top"><div class="week-btn-wrap"><span @click="getLastWeek">上周</span><span @click="getCurWeek">本周</span><span @click="getNextWeek">下周</span></div><span class="w-today-date"> {{ todayDate }}</span><div class="w-choose-status"><div v-for="sta in cardStatus"><span class="square" :style="{background:sta.color}"></span><span class="title">{{ sta.title }}</span></div></div></div><div class="week-table"><div class="table-header"><div class="table-week"><template v-for="(item,index) of weeks"><span class="w-first" v-if="index===0" :key="index">{{ item }}</span><span v-else :key="index">{{ item }}</span></template></div><div class="w-table-date"><template v-for="(item,index) of months"><span class="w-first" v-if="index===0" :key="index"></span><template v-else><span :key="index" class="w-day-item" :class="{'w-isCurDate':item&&item.isCurDate}">{{ `${item && item.isCurDate ? item && item.showDate + '(今天)' || '' : item && item.showDate || ''}` }}</span></template></template></div></div><div class="w-time-period-list"><ul class="w-time-period-row"><!--循环时段,看时段有多少个--><template v-if="planList.length>0"><li class="w-time-period-col" v-for="(period,p_index) in planList":key="`period${p_index}`"><!--第一列显示时段--><div class="w-time-period"> {{ period.timePeriod }}</div><!-- 后面显示周一到周日的计划--><div class="w-row-day"><!-- 循环显示每周的日期--><template v-for="(month,m_index) of months"><!-- v-if="month" 去除数据处理的时候移除数组第一个为empty的问题--><div v-if="month" :key="`month${m_index}`" class="w-things" @click="handleCardDetail(month,period)"><!-- 循环每个时间段的计划--><template v-for="(card,t_index) of period.schedule"><template v-for="(single,sIndex) in card[month.date]"><template v-if="!card.isExpend"><div v-if="single.date===month.date&&sIndex<hasNumExpend":key="`thing${sIndex}`"class="w-thing-item"@click="handleDetail(single)":style="{background: cardStatus[single.status].color}"><slot name="thing" :row="single"></slot></div></template><template v-if="card.isExpend"><div v-if="single.date===month.date":key="`thing${sIndex}`"class="w-thing-item"@click="handleDetail(single)":style="{background: cardStatus[single.status].color}"><slot name="thing" :row="single"></slot></div></template><div class="w_expand"v-if="card[month.date].length>hasNumExpend&&(card[month.date].length-1)===sIndex&&!card.isExpend&&single.date===month.date"@click="handleExpand(card)">展开</div><div class="w_shrink"v-if="card[month.date].length>hasNumExpend&&(card[month.date].length-1)===sIndex&&card.isExpend&&single.date===month.date"@click="handleExpand(card)">收缩</div></template></template></div></template></div></li></template><div class="w-noMore" v-else><span>暂无数据</span></div></ul></div></div></div>
</template><script>
import { formatDate , getCurDay } from "@/utils/weekTools";export default {name: 'WeekSchedule',props: {planList: {type: Array,default: []},//卡片状态cardStatus: {type: Object,default: () => {return {1: {title: '已过期',color: '#9CADADB7'},2: {title: '进行中',color: '#FF6200'},3: {title: '未开始',color: '#3291F8'},}}},//第一列是星期几isFirstDayOfMondayOrSunday: {type: Number,default: 1,},hasNumExpend:{type:Number,default:2}},data () {return {weeks: ['时段', '周一', '周二', '周三', '周四', '周五', '周六', '周日',],todayDate: '',months: [],curDate: '',nowDate: new Date(),}},watch: {isFirstDayOfMondayOrSunday: {handler (val) {if (val > 1) {let arr = ['周一', '周二', '周三', '周四', '周五', '周六', '周日']const arr1 = arr.slice(val - 1)const arr2 = arr.slice(0, val - 1)this.weeks = ['时段', ...arr1, ...arr2]}},immediate: true}},mounted () {this.getCurWeek()},methods: {//展开与缩放操作handleExpand (row) {row.isExpend = !row.isExpend},/*** 获取 时间* @param time*/getWeek (time) {this.curDate = new Date(time)//当前是周几const whichDay = time.getDay()let num = 0if (this.isFirstDayOfMondayOrSunday <= whichDay) {num = this.isFirstDayOfMondayOrSunday} else {num = this.isFirstDayOfMondayOrSunday - 7}const weekDay = time.getDay() - numtime = this.addDate(time, weekDay * -1)for (let i = 0; i < 7; i++) {const { year, month, day } = formatDate(i === 0 ? time : this.addDate(time, 1))this.months.push({date: `${year}-${month}-${day}`,showDate: `${month}-${day}`,timestamp: new Date(`${year}-${month}-${day}`).getTime()})}this.months.sort((a, b) => a.timestamp - b.timestamp)delete this.months[0]this.todayDate = `${this.months[1].date} ~ ${this.months[this.months.length - 1].date}`},/*** 处理日期* @param date* @param n* @returns {*}*/addDate (date, n) {date.setDate(date.getDate() + n)return date},/*** 上周*/getLastWeek () {const date = this.addDate(this.curDate, -7),{ year, month, day } = formatDate(date),dateObj = {date: `${year}-${month}-${day}`,timestamp: new Date(`${year}-${month}-${day}`).getTime()}this.dealDate(date)this.$emit('changeWeek', dateObj)},/*** 本周*/getCurWeek () {const { year, month, day } = formatDate(new Date()),dateObj = {date: `${year}-${month}-${day}`,timestamp: new Date(`${year}-${month}-${day}`).getTime()}this.dealDate(new Date())this.$emit('changeWeek', dateObj)},/*** 下周*/getNextWeek () {const date = this.addDate(this.curDate, 7),{ year, month, day } = formatDate(date),dateObj = {date: `${year}-${month}-${day}`,timestamp: new Date(`${year}-${month}-${day}`).getTime()}this.dealDate(date)this.$emit('changeWeek', dateObj)},/*** 显示当天日期状态* @param date*/dealDate (date) {this.months = ['']this.getWeek(date)const curDate = getCurDay()this.months.forEach(item => {item.isCurDate = item.date === curDate})},/*** 点击卡片子内容查看详情* @param row*/handleDetail (row) {this.$emit('handleDetail', row)},/*** 点击卡片查看全部内容* @param month* @param period*/handleCardDetail (month, period) {this.$emit('handleCardDetail', { ...month, ...period })}}
}
</script><style>
ul {list-style: none;
}ul, li {margin: 0;padding: 0;
}.course-week {width: 100%;border: 1px solid #ddd;padding: 1%;box-sizing: border-box;
}.week-top {display: flex;justify-content: space-between;align-items: center;width: 100%;height: 40px;padding: 0 1%;box-sizing: border-box;}.week-top .week-btn-wrap {width: 200px;display: flex;justify-content: space-around;color: #409EFF;
}.week-top .week-btn-wrap span {cursor: pointer;display: flex;justify-content: center;align-items: center;font-size: 15px;
}.w-today-date {font-weight: bold;font-size: 16px;
}.w-choose-status {display: flex;justify-content: flex-end;width: 200px;
}.w-choose-status > div {width: 100%;flex: 1;display: flex;padding: 0 2%;white-space: nowrap;line-height: 20px;box-sizing: border-box;
}.w-choose-status > div .square {display: flex;width: 16px;height: 16px;border-radius: 4px;box-sizing: border-box;
}.w-choose-status > div .title {display: flex;align-items: center;line-height: 16px;padding-left: 4px;font-size: 14px;box-sizing: border-box;
}.week-table {display: flex;flex-direction: column;
}.week-table .table-header {width: 100%;height: 80px;background: #EAEDF2;display: flex;flex-direction: column;align-items: center;border-bottom: 1px solid #EAEDF2;box-sizing: border-box;
}.table-header .w-table-date, .table-week {width: 100%;height: 40px;text-align: left;display: flex;justify-content: center;align-items: center;}.table-header .w-table-date > span, .table-week > span {flex: 1;color: #000;height: 100%;font-size: 14px;display: flex;justify-content: center;align-items: center;font-weight: bold;
}.w-table-date .w-day-item, .table-week .w-day-item {color: #000;font-size: 14px;display: flex;justify-content: center;align-items: center;
}.week-table .w-time-period-list {width: 100%;
}.w-time-period-list .w-time-period-row {width: 100%;min-height: 60px;
}.w-time-period-col {width: 100%;min-height: 60px;display: flex;
}.w-time-period-col .w-time-period {width: 12.5%;display: flex;justify-content: center;align-items: center;border-left: 1px solid #EAEDF2;border-bottom: 1px solid #EAEDF2;box-sizing: border-box;
}.w-time-period-col .w-row-day {width: 87.5%;display: flex;justify-content: center;
}.w-row-day .w-things {flex: 1;display: flex;flex-direction: column;align-items: center;border-left: 1px solid #EAEDF2;border-bottom: 1px solid #EAEDF2;box-sizing: border-box;
}.w-row-day .w-things:last-child {border-right: 1px solid #EAEDF2;
}.w-things .w-thing-item {display: flex;width: 80%;font-size: 14px;flex-direction: column;justify-content: space-around;min-height: 90px;border-radius: 10px;margin: 2% 1%;padding: 1% 2%;cursor: pointer;color: #fff;background: #FF6200;box-sizing: border-box;transition: all 1s linear .5s;
}.w-isCurDate {color: #FF2525 !important;
}.w-noMore {min-height: 200px;padding: 2%;display: flex;justify-content: center;align-items: center;border: 1px solid rgba(156, 173, 173, 0.3);color: #9CADADB7;box-sizing: border-box;
}.w_expand, .w_shrink {color: #0A98D5;cursor: pointer;width: 100%;padding: 2% 0;display: flex;justify-content: center;align-items: center;box-sizing: border-box;
}
</style>
js代码 weekTools.js
/*** 唯一的随机字符串,用来区分每条数据* @returns {string}*/
export function getUid() {return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, (c) => {const r = (Math.random() * 16) | 0;const v = c === 'x' ? r : (r & 0x3) | 0x8;return v.toString(16);});
}/*** 计算时间差* @param beginTime:2022-01-13* @param endTime:2022-01-13* @returns {{hours: number, seconds: number, minutes: number, day: number}}*/
export function dealTime(beginTime, endTime) {var dateBegin = new Date(beginTime);var dateEnd = new Date(endTime);var dateDiff = dateEnd.getTime() - dateBegin.getTime(); //时间差的毫秒数var day = Math.floor(dateDiff / (24 * 3600 * 1000)); //计算出相差天数var leave1 = dateDiff % (24 * 3600 * 1000); //计算天数后剩余的毫秒数var hours = Math.floor(leave1 / (3600 * 1000)); //计算出小时数//计算相差分钟数var leave2 = leave1 % (3600 * 1000); //计算小时数后剩余的毫秒数var minutes = Math.floor(leave2 / (60 * 1000)); //计算相差分钟数//计算相差秒数var leave3 = leave2 % (60 * 1000); //计算分钟数后剩余的毫秒数var seconds = Math.round(leave3 / 1000);return {day,hours,minutes,seconds}
}/*** 获取当天时间* @returns {string}*/
export function getCurDay() {var datetime = new Date();var year = datetime.getFullYear();var month = datetime.getMonth() + 1 < 10 ? "0" + (datetime.getMonth() + 1) : datetime.getMonth() + 1;var date = datetime.getDate() < 10 ? "0" + datetime.getDate() : datetime.getDate();return `${year}-${month}-${date}`
}// 日期格式处理
export function formatDate(date) {var year = date.getFullYear();var months = date.getMonth() + 1;var month = (months < 10 ? '0' + months : months).toString();var day = (date.getDate() < 10 ? '0' + date.getDate() : date.getDate()).toString();return {year: year.toString(),month,day}
}/*** 数组中,某个属性相同的数据放在一块,如把某个日期相同的相连一起* @param list 传入的数组* @param prop 那个属性相同的数据* @returns {*[]}*/
export function margePropData(list = [], prop) {let arr = [], tempArr = {};list.forEach(item => {if (!tempArr[item[prop]]) {tempArr[item[prop]] = [item]} else {tempArr[item[prop]].push(item)}})for (const tempArrKey in tempArr) {arr = [...arr, ...tempArr[tempArrKey]]}return arr
}/*** 合并行* @param list* @param prop*/
export function mergeRows(list = [], prop) {list.forEach(ele => {ele.rowspan = 1})const len = list.lengthfor (let i = 0; i < len; i++) {for (let j = i + 1; j < len; j++) {if (list[i][prop] === list[j][prop]) {list[i].rowspan++list[j].rowspan--}}// 这里跳过已经重复的数据i = i + list[i].rowspan - 1}return list
}/*** 根据当前数据的位置,在数组中插入数据* 如数组【1,2,4,5】想要在2后面插入3,*1:首先获取到2的下标,*2:然后获取要插入之前的数据,获取要插入之后的数据,中间就是插入的位置*3:最后把这三个按顺序合并就得到在想要的位置插入数据* @param list* @param index* @param target*/
export function insertArrPositionOfIndex(list = [], index = 0, target = {}) {//根据index 找出小于index的数据放在左边const leftList = list.filter((t, i) => i < index);//根据index 找出大于index的数据放在右边const rightList = list.filter((t, i) => i >= index);// 最终合并数据return [...leftList, target, ...rightList]
}/*** 校验规则*/
export function verifyRules(list = [], require = []) {let message = nullfor (const key of require) {const isEmpty = list.every(it => !it[key.prop])if (isEmpty) {message = key.messagebreak;}}return message
}/*** 获取元素下标* @param dir 为 1:得到正序遍历方法;为 -1: 得到逆序遍历方法。* @returns {(function(*, *, *=): (number|number|number))|*}*/
export function findArrIndex(dir = 1) {return function (array, cb, context) {let length = array.length;// 控制初始 index,0 或者 length-1let index = dir >= 0 ? 0 : length - 1;// 条件: 在数组范围内;// 递增或递减:递加 1 或者 -1; 妙啊~for (; index >= 0 && index <= length - 1; index += dir) {if (cb.call(context, array[index], index)) return index}return -1}
}/*** map转换成数组* @param target* @returns {*[]}* @constructor*/
export function MapConvertArr(target = {}) {let list = [];for (let key in target) {list.push(target[key]);}return list;
}/*** 对象数组去重* @param arr 数组* @param prop 根据什么字段去重* @returns {any[]}*/
export function arrayDeduplication(arr, prop) {let map = new Map();return arr.filter(item => !map.has(item[prop]) && map.set(item[prop], 1));
}/*** 获取当前天时间* @param param 【Y:年;M:月;D:日;h:小时;m:分钟;s:秒;】 默认精确到秒* @returns {*}*/
export function getCurrentDate(param = 's') {var now = new Date();var year = now.getFullYear(); //得到年份var month = now.getMonth();//得到月份var date = now.getDate();//得到日期var day = now.getDay();//得到周几var hour = now.getHours();//得到小时var minu = now.getMinutes();//得到分钟var sec = now.getSeconds();//得到秒month = month + 1;if (month < 10) month = "0" + month;if (date < 10) date = "0" + date;if (hour < 10) hour = "0" + hour;if (minu < 10) minu = "0" + minu;if (sec < 10) sec = "0" + sec;const arr = {'Y': year,'M': year + "-" + month,'D': year + "-" + month + "-" + date,'h': year + "-" + month + "-" + date + " " + hour,'m': year + "-" + month + "-" + date + " " + hour + ":" + minu,'s': year + "-" + month + "-" + date + " " + hour + ":" + minu + ":" + sec}return arr[param];
}/*** 获取当天时间前后七天时间* @param day day>0 当天时间的后几天 day<0 当天时间前几天* @returns {string}*/
export function getRecentDate(day) {var date1 = new Date(),time1 = date1.getFullYear() + "-" + (date1.getMonth() + 1) + "-" + date1.getDate();//time1表示当前时间var date2 = new Date(date1);date2.setDate(date1.getDate() + day);const y = date2.getFullYear();const m = (date2.getMonth() + 1) > 9 ? (date2.getMonth() + 1) : '0' + (date2.getMonth() + 1)const d = date2.getDate() > 9 ? date2.getDate() : '0' + date2.getDate()return y + "-" + m + "-" + d;
}export function MyDebounce(fn, duration = 100) {let timer = nullreturn (...args) => {clearTimeout(timer)timer = setTimeout(() => {fn(...args);}, duration)}
}export function MyThrottle(fn, duration = 100) {let target = true;return (...arg) => {if (!target) {return false;}target = false;setTimeout(() => {fn(...arg);target = true}, duration)}
}
查看全文
99%的人还看了
相似问题
猜你感兴趣
版权申明
本文"vue 自己捣鼓周日程日历组件":http://eshow365.cn/6-30287-0.html 内容来自互联网,请自行判断内容的正确性。如有侵权请联系我们,立即删除!
- 上一篇: pytorch笔记 GRUCELL
- 下一篇: 实习常用代码——【CSS样式】