Vue 组件(component)之 精美的日历
公司的要求,需要开发一个精美的日历组件(IOS , 安卓, PC 的IE9+都能运行),写完后想把它分享出来,希望大家批评()。
先来个截图 代码已经分享到 https://github.com/zhangKunUserGit/vue-component
根据需求先说一下怎么用吧 (上面是:HTML, 下面是JS )
<date-picker
v-if="showDatePicker"
:date="date"
:min-date="minDate"
:max-date="maxDate"
@confirm="confirm"
@cancel="cancel"
></date-picker>
import DatePicker from './components/DatePicker.vue';
import './style.scss'; new Vue({
el: '#app',
data() {
return {
date: '2017-09-11',
minDate: '2000-09-11',
maxDate: '2020-09-11',
showDatePicker: false,
selectedDate: '点击选择日期',
};
},
methods: {
openDatePicker() {
this.showDatePicker = true;
},
confirm(value) {
this.showDatePicker = false;
this.selectedDate = value;
},
cancel() {
this.showDatePicker = false;
},
},
components: {
DatePicker,
},
});
我们提供了最大值、最小值和初始值,唯一不足的地方是时间格式只能是YYYY-MM-DD (2017-12-12) ,大家可以从github上拉取代码运行看一下(由于没有仔细测试,可能会有bug和性能问题,希望指出)。
(一)先画好界面
这个不是重点,HTML 和 CSS,应该很简单,大家看我的css 可能感觉我的命名太长了,只因为我们公司用,担心其他样式影响它(可能有其他方式吧,希望大神指出)
(二)组装日期列表
先看代码:
rows() {
const { year, month } = this.showDate;
const months = (new Date(year, month, 0)).getDate();
const result = [];
let row = [];
let weekValue;
// 按照星期分组
for (let i = 1; i <= months; i += 1) {
// 根据日期获取星期,并让开头是1,而非0
weekValue = (new Date(year, month, i)).getDay() + 1;
// 判断月第一天在星期几,并填充前面的空白区域
if (i === 1 && weekValue !== 1) {
this.addRowEmptyValue(row, weekValue);
this.addRowDayValue(row, i);
} else {
this.addRowDayValue(row, i);
// 判断月最后一天在星期几,并填充后面的空白区域
if (i === months && weekValue !== 7) {
this.addRowEmptyValue(row, (7 - weekValue) + 1);
}
}
// 按照一周分组
if (weekValue % 7 === 0 || i === months) {
result.push(row);
row = [];
}
}
this.showDate.monthStr = monthJson[this.showDate.month];
return result;
},
我的思路是:
(1)获取月份天数,并按照星期分组;
(2)如果月份第一天不在星期一,前面填充空值。同理,如何月份最后一天不在周日,最后面填充空值,目的是:让分的组 长度都是7,也就是一周。这样可以用flex布局方式快速开发了;
(3)里面也包含一些限制,比如小于minDate和大于maxDate, 不让点击等等
(三)切换月份
(1)上一个月份
/**
* 切换到上一个月
*/
prevMonth() {
if (this.prevMonthClick) {
return;
}
this.prevMonthClick = true;
setTimeout(() => {
this.prevMonthClick = false;
}, 500);
this.fadeXType = 'fadeX_Prev';
// 如何当前月份已经小于等于minMonth 就不让其在执行
if (this.isMinLimitMonth()) {
return;
}
const { year, month } = this.showDate;
// 判断当前月份,如果已经等于1(1就是一月,而不是二月)
if (month <= 1) {
this.showDate.year = year - 1;
this.showDate.month = 12;
} else {
this.showDate.month -= 1;
}
},
setTimeout()主要是让其显示动画后自动消失。 fadeXType 是动画类型
(2)下一个月份
/**
* 切换到下一个月
*/
nextMonth() {
if (this.nextMonthClick) {
return;
}
this.nextMonthClick = true;
setTimeout(() => {
this.nextMonthClick = false;
}, 500);
this.fadeXType = 'fadeX_Next';
// 如何当前月份已经大于等于maxMonth 就不让其在执行
if (this.isMaxLimitMonth()) {
return;
}
const { year, month } = this.showDate;
// 判断当前月份,如果已经等于12(12就是十二月)
if (month >= 12) {
this.showDate.year = year + 1;
this.showDate.month = 1;
} else {
this.showDate.month += 1;
}
},
这里面的setTimeout() 和prevMonth方法的原理一样。
上面两种切换月份的功能主要注意:
a. 因为有minDate和maxDate,所以首先考虑的是不能超出这个限制。
b. 要考虑切换月份后年的变化,当月份大于12后,年加1 ,月变成 1。
(四)选择年份
(1)点击最上面的年,显示年份列表
openYearList() {
if (this.showYear) {
this.showYear = false;
return;
}
const index = this.yearList.indexOf(this.selectDate.year);
this.showYear = true;
// 打开年列表,让其定位到选中的位置上
setTimeout(() => {
this.$refs.yearList.scrollTop = (index - 3) * 40;
});
},
(2)选择年份
selectYear(value) {
this.showYear = false;
this.showDate.year = value;
let type;
// 当日期在最小值之外,月份换成最小值月份 或者 当日期在最大值之外,月份换成最大值月份
if (this.isMinLimitMonth()) {
type = 'copyMinDate';
} else if (this.isMaxLimitMonth()) { // 当日期在最大值之外,月份换成最大值月份
type = 'copyMaxDate';
}
if (type) {
this.showDate.month = this[type].month;
this.showDate.day = this[type].day;
this.resetSelectDate(this.showDate.day);
return;
}
let dayValue = this.selectDate.day;
// 判断日是最大值,防止另一个月没有这个日期
if (this.selectDate.day > 28) {
const months = (new Date(this.showDate.year, this.showDate.month, 0)).getDate();
// 当前月份没有这么多天,就把当前月份最大值赋值给day
dayValue = months < dayValue ? months : dayValue;
}
this.resetSelectDate(dayValue);
},
在切换年份时注意一下方面:
a. 考虑minDate和maxDate, 因为如果之前你选择的月份是1月,但是限制是9月,在大于minDate(比如2017) 年份没有问题,但是到了minDate 的具体年份(比如2010),那么月份最小值只能是九月,需要修改月份,maxDate同理。
b. 如何之前你选择的day是31,由于切换年份后,这个月只有30天,记得把day 换成这个月最大值,也就是30。
(五)处理原始数据
其实这一条正常情况下,应该放在第一步讲,但是我是根据我的开发习惯来写步骤的。我一般都是先写功能,数据是模拟的,等写好了,再考虑原始数据格式和暴露具体的方法等等,因为这样不会改来改去,影响开发和心情。
initDatePicker() {
this.showDate = { ...this.splitDate(this.date, true) };
this.copyMinDate = { ...this.splitDate(this.minDate) };
this.copyMaxDate = { ...this.splitDate(this.maxDate) };
this.selectDate = { ...this.showDate };
},
splitDate(date, addStr) {
let result = {};
const splitValue = date.split('-');
try {
if (!splitValue || splitValue.length < 3) {
throw new Error('时间格式不正确');
}
result = {
year: Number(splitValue[0]),
month: Number(splitValue[1]),
day: Number(splitValue[2]),
};
if (addStr) {
result.week = (new Date(result.year, result.month, result.day)).getDay() + 1;
result.monthStr = monthJson[result.month];
result.weekStr = weekJson[result.week];
}
} catch (error) {
console.error(error);
}
return result;
},
这里目的是:
a. 处理原始数据,把原始数据查分,用json缓存下来,这样方便后面操作和显示。这里面我只兼容YYYY-MM-DD的格式,其他的都不兼容,如果你想兼容其他格式,你可以修改其代码,或者用moment.js 等其他库帮你做这件事情。
b. 拆分后的格式如下:
year: '',
month: '',
day: '',
week: '',
weekStr: '',
monthStr: '',
总结:
上面就是开发这个组件的详细讲解,如有不妥,请指出批评。 仔细想想,其实这个不难,就是有点琐碎。仔细就好
这里的所有动画都是用的Vue 的 transition,大家可以看看官网,非常详细。
Vue 组件(component)之 精美的日历的更多相关文章
- Vue组件component创建及使用
组件化与模块化的区别 什么是组件:组件的出现,就是为了拆分Vue实例的代码量,能够让我们以不同的组件,来划分不同的功能模块 ,将来我们需要什么功能,就可以去调用对应的组件即可 组件化与模块化的不同: ...
- 二、Vue组件(component):组件的相互引用、通过props实现父子组件互传值
一.组件各部分说明及互相引用 1.一个vue组件由三个部分组成 Template 只能存在一个根元素 2.Script 3.Style scoped:样式只在当前组件内生效 1.1 组件的基本引用代码 ...
- 怎样创建并使用 vue 组件 (component) ?
组件化开发 需要使用到组件, 围绕组件, Vue 提供了一系列功能方法, 这里仅记录组件的 最简单 的使用方法. 1. 通过 Vue.component(tagName, options) 注册一个 ...
- vue组件component没效果
如果实在不知道问题所在,你就看看你的component的命名是不是驼峰命名
- vue组件大集合 component
vue组件分为全局组件.局部组件和父子组件,其中局部组件只能在el定义的范围内使用, 全局组件可以在随意地方使用,父子组件之间的传值问题等. Vue.extend 创建一个组件构造器 template ...
- vue从入门到进阶:组件Component详解(六)
一.什么是组件? 组件 (Component) 是 Vue.js 最强大的功能之一.组件可以扩展 HTML 元素,封装可重用的代码.在较高层面上,组件是自定义元素,Vue.js 的编译器为它添加特殊功 ...
- 前端性能优化成神之路--vue组件懒加载(Vue Lazy Component )
---恢复内容开始--- 使用组件懒加载的原因 我们先来看看这样的一个页面,页面由大量模块组成,所有模块是同时进行加载,模块中图片内容较多,每个模块的依赖资源较多(包括js文件.接口文件.css文件等 ...
- Vue教程:组件Component详解(六)
一.什么是组件? 组件 (Component) 是 Vue.js 最强大的功能之一.组件可以扩展 HTML 元素,封装可重用的代码.在较高层面上,组件是自定义元素,Vue.js 的编译器为它添加特殊功 ...
- vue19 组建 Vue.extend component、组件模版、动态组件
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...
随机推荐
- pipelineDB里Combine用法
combine only works on aggregate columns that belong to continuous views. 创建CONTINUOUS CREATE CONTINU ...
- python-02 数据类型、字符编码、文件处理
标准数据类型 Python3 中有六个标准的数据类型: Number(数字) String(字符串) List(列表) Tuple(元组) Sets(集合) Dictionary(字典) 数字 #整型 ...
- spfa_dfs找负环
luogu #include<iostream> #include<cstdio> #include<cstring> #include<vector> ...
- java 之 命令模式(大话设计模式)
命令模式,笔者一直以为当我们开发的过程中基本上很难用到,直到维护阶段或者重构阶段,我们会发现有些撤销命令和追加命令比较频繁时,自然而然就用到命令模式. 先看下类图 大话设计模式-类图 简单说下类图,最 ...
- Loadrunner 读取文件
char buffer[1000]; long file_stream; char * filename = "d:\log.txt"; file_stream=fopen(fil ...
- 高版本号chrome安装flashplayer debuger后无法使用的问题
起因应该是苹果公司指出flash player的安全问题,还有各种原因导致google将在未来取消NPAPI的支持,所以fp们就悲剧了在高版本号chrome(42以上)默认是关闭外部安装的插件使用的, ...
- ios怎么推断日期是周末?
- (NSString *)calculateWeek:(NSDate *)date{ //计算week数 NSCalendar * myCalendar = [NSCalendar currentC ...
- hdu 4409 Family Name List(LCA&有坑点)
Family Name List Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others) ...
- Java中string 创建对象时 “”和null的差别
null和""的差别 问题一: null和""的差别 String s=null; string.trim()就会抛出为空的exception String s ...
- js清除cookie有时无法清除
最近写页面遇到一个问题,退出的时候需要清除cookie,但是刚开始一直清除不掉,代码如下: //清除函数 function delCookie(name) { var date= new Date() ...