Vue 组件(component)教程之实现精美的日历方法示例


Posted in Javascript onJanuary 08, 2018

组件(component)是Vue最强大的功能之一。组件可以扩展HTML元素,封装可重用的代码,根据项目需求,抽象出一些组件,每个组件里包含了展现、功能和样式。每个页面,根据自己的需要,使用不同的组件来拼接页面。这种开发模式使得前端页面易于扩展,且灵活性高,而且组件之间也实现了解耦。

最近应公司的要求,需要开发一个精美的日历组件(IOS , 安卓, PC 的IE9+都能运行),写完后想把它分享出来,希望大家批评。

先来个截图

Vue 组件(component)教程之实现精美的日历方法示例  

 代码已经分享到 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 DataPicker 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: {
 DataPicker,
 },
});

我们提供了最大值、最小值和初始值,唯一不足的地方是时间格式只能是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,大家可以看看官网,非常详细。

好了,以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作具有一定的参考学习价值,如果有疑问大家可以留言交流,谢谢大家对三水点靠木的支持。

Javascript 相关文章推荐
用javascript实现给图片加链接
Aug 15 Javascript
Javascript 异步加载详解(浏览器在javascript的加载方式)
May 20 Javascript
js中的push和join方法使用介绍
Oct 08 Javascript
javascript将url中的参数加密解密代码
Nov 17 Javascript
AngularJS实现分页显示数据库信息
Jul 01 Javascript
jQuery stop()用法实例详解
Jul 28 Javascript
jquery html5 视频播放控制代码
Nov 06 Javascript
微信小程序(六):列表上拉加载下拉刷新示例
Jan 13 Javascript
微信小程序 共用变量值的实现
Jul 12 Javascript
webpack打包js的方法
Mar 12 Javascript
js+HTML5 canvas 实现简单的加载条(进度条)功能示例
Jul 16 Javascript
Smartour 让网页导览变得更简单(推荐)
Jul 19 Javascript
一步步教你利用webpack如何搭一个vue脚手架(超详细讲解和注释)
Jan 08 #Javascript
深入理解 webpack 文件打包机制(小结)
Jan 08 #Javascript
webpack构建的详细流程探底
Jan 08 #Javascript
详解ES6中的代理模式——Proxy
Jan 08 #Javascript
Vue v2.4中新增的$attrs及$listeners属性使用教程
Jan 08 #Javascript
实例解析ES6 Proxy使用场景介绍
Jan 08 #Javascript
详解weex默认webpack.config.js改造
Jan 08 #Javascript
You might like
Fatal error: Call to undefined function curl_init()解决方法
2010/04/09 PHP
Smarty模板学习笔记之Smarty简介
2014/05/20 PHP
基于PHP的简单采集数据入库程序【续篇】
2014/07/30 PHP
php获取目录中所有文件名及判断文件与目录的简单方法
2017/03/04 PHP
PHP实现网站访问量计数器
2017/10/27 PHP
基于jQuery实现下拉收缩(展开与折叠)特效
2012/12/25 Javascript
jQuery弹出(alert)select选择的值
2013/04/21 Javascript
js二维数组排序的简单示例代码
2014/01/24 Javascript
jquery制作LED 时钟特效
2015/02/01 Javascript
javascript实现手机震动API代码
2015/08/05 Javascript
JavaScript数组的栈方法与队列方法详解
2016/05/26 Javascript
JS当前页面登录注册框,固定DIV,底层阴影的实例代码
2016/09/29 Javascript
JavaScript实现页面无操作倒计时退出
2016/10/22 Javascript
Bootstrap Search Suggest使用例子
2016/12/21 Javascript
Angular2实现自定义双向绑定属性
2017/03/22 Javascript
Angular.JS利用ng-disabled属性和ng-model实现禁用button效果
2017/04/05 Javascript
JS图片预加载插件详解
2017/06/21 Javascript
推荐15个最好用的JavaScript代码压缩工具
2019/02/13 Javascript
VueJs里利用CryptoJs实现加密及解密的方法示例
2019/04/29 Javascript
JavaScript布尔运算符原理使用解析
2020/05/06 Javascript
使用node-media-server搭建一个简易的流媒体服务器
2021/01/20 Javascript
[02:40]DOTA2殁境神蚀者 英雄基础教程
2013/11/26 DOTA
[05:09]DOTA2-DPC中国联赛2月22日Recap集锦
2021/03/11 DOTA
python实现简易云音乐播放器
2018/01/04 Python
python基于itchat模块实现微信防撤回
2019/04/29 Python
在python中实现同行输入/接收多个数据的示例
2019/07/20 Python
Python datetime包函数简单介绍
2019/08/28 Python
python 实现单通道转3通道
2019/12/03 Python
IE矩阵Matrix滤镜旋转与缩放及如何结合transform
2012/11/29 HTML / CSS
数据库笔试题
2013/05/09 面试题
《青山处处埋忠骨》教学反思
2014/04/22 职场文书
安康杯竞赛活动总结
2014/05/05 职场文书
提拔干部考察材料
2014/05/26 职场文书
2016秋季田径运动会广播稿
2015/12/21 职场文书
导游词之广州陈家祠
2019/10/21 职场文书
详解Java实践之抽象工厂模式
2021/06/18 Java/Android