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 寻址,闭包,对象模型和相关问题
Apr 27 Javascript
js event事件的传递与冒泡处理
Dec 06 Javascript
jQuery(非HTML5)可编辑表格实现代码
Dec 11 Javascript
js时间比较示例分享(日期比较)
Mar 05 Javascript
jQuery实现固定在网页顶部的菜单效果代码
Sep 02 Javascript
基于Bootstrap里面的Button dropdown打造自定义select
May 30 Javascript
Ajax基础知识详解
Feb 17 Javascript
JS使用cookie实现只出现一次的广告代码效果
Apr 22 Javascript
VUE 3D轮播图封装实现方法
Jul 03 Javascript
微信小程序之多列表的显示和隐藏功能【附源码】
Aug 06 Javascript
axios实现文件上传并获取进度
Mar 25 Javascript
vue实现给div绑定keyup的enter事件
Jul 31 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
浅析PHP中strlen和mb_strlen的区别
2014/08/31 PHP
四个PHP非常实用的功能
2015/09/29 PHP
php使用PDO获取结果集的方法
2017/02/16 PHP
可以把编码转换成 gb2312编码lib.UTF8toGB2312.js
2007/08/21 Javascript
json 实例详细说明教程
2009/10/31 Javascript
EXT中xtype的含义分析
2010/01/07 Javascript
页面调用单个swf文件,嵌套出多个方法。
2011/11/21 Javascript
Javascript获取窗口(容器)的大小及位置参数列举及简要说明
2012/12/09 Javascript
jquery 取子节点及当前节点属性值的方法
2014/08/24 Javascript
JS简单模拟触发按钮点击功能的方法
2015/11/30 Javascript
jQuery鼠标事件总结
2016/10/13 Javascript
vue自定义全局共用函数详解
2018/09/18 Javascript
小程序实现选择题选择效果
2018/11/04 Javascript
JavaScript面试中常考的字符串操作方法大全(包含ES6)
2020/05/10 Javascript
Python实现统计英文单词个数及字符串分割代码
2015/05/28 Python
Python中将字典转换为XML以及相关的命名空间解析
2015/10/15 Python
Python原始字符串与Unicode字符串操作符用法实例分析
2017/07/22 Python
Python二进制串转换为通用字符串的方法
2018/07/23 Python
利用Pycharm断点调试Python程序的方法
2018/11/29 Python
Python3转换html到pdf的不同解决方案
2019/03/11 Python
python解释器spython使用及原理解析
2019/08/24 Python
python将时分秒转换成秒的实例
2019/12/07 Python
python实现ip地址的包含关系判断
2020/02/07 Python
解决Tensorboard 不显示计算图graph的问题
2020/02/15 Python
python两个list[]相加的实现方法
2020/09/23 Python
中国领先的汽车保养服务平台:途虎养车
2019/10/18 全球购物
高校优秀辅导员事迹材料
2014/05/07 职场文书
高一军训的心得体会
2014/09/01 职场文书
党员学习群众路线教育实践活动对照检查材料
2014/09/23 职场文书
“向国旗敬礼”活动策划方案(4篇)
2014/09/27 职场文书
党的群众路线教育实践活动个人对照检查材料(校长)
2014/11/05 职场文书
三行辞职书范文
2015/02/26 职场文书
2015年安全保卫工作总结
2015/05/14 职场文书
《梅花魂》教学反思
2016/02/18 职场文书
财产分割协议书
2016/03/22 职场文书
三种方式清除vue路由跳转router-link的历史记录
2022/04/10 Vue.js