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 document.createDocumentFragment()
Apr 04 Javascript
javascript tips提示框组件实现代码
Nov 19 Javascript
JS跨域总结
Aug 30 Javascript
JS实用的动画弹出层效果实例
May 05 Javascript
jquery 抽奖小程序实现代码
Oct 12 Javascript
JS实现的走迷宫小游戏完整实例
Jul 19 Javascript
简单实现jQuery弹窗效果
Oct 30 jQuery
Vue 全家桶实现移动端酷狗音乐功能
Nov 16 Javascript
json数据格式常见操作示例
Jun 13 Javascript
VUE 组件转换为微信小程序组件的方法
Nov 06 Javascript
浅析vue cli3 封装Svgicon组件正确姿势(推荐)
Apr 27 Javascript
微信小程序实现带放大效果的轮播图
May 26 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
虫族 Zerg 热键控制
2020/03/14 星际争霸
php及codeigniter使用session-cookie的方法(详解)
2017/04/06 PHP
一个js封装的不错的选项卡效果代码
2008/02/15 Javascript
Javascript常考语句107条收集
2010/03/09 Javascript
jquery 简短几句代码实现给元素动态添加及获取提示信息
2011/09/01 Javascript
location对象的属性和方法应用(解析URL)
2013/04/12 Javascript
关于Javascript与iframe的那些事儿
2013/07/04 Javascript
轻松创建nodejs服务器(2):nodejs服务器的构成分析
2014/12/18 NodeJs
jQuery实现菜单式图片滑动切换
2015/03/14 Javascript
JavaScript数组去重的五种方法
2015/11/05 Javascript
微信小程序-消息提示框实例
2016/11/24 Javascript
纯原生js实现table表格的增删
2017/01/05 Javascript
JS中input表单隐藏域及其使用方法
2017/02/13 Javascript
AngularJS模糊查询功能实现代码(过滤内容下拉菜单排序过滤敏感字符验证判断后添加表格信息)
2017/10/24 Javascript
vue里的data要用return返回的原因浅析
2019/05/28 Javascript
jquery实现的分页显示功能示例
2019/08/23 jQuery
vue实现拖拽进度条
2021/03/01 Vue.js
Python实现提取文章摘要的方法
2015/04/21 Python
介绍Python的Django框架中的静态资源管理器django-pipeline
2015/04/25 Python
Python中用于转换字母为小写的lower()方法使用简介
2015/05/19 Python
在Python的Django框架中使用通用视图的方法
2015/07/21 Python
图文详解WinPE下安装Python
2016/05/17 Python
Python登录并获取CSDN博客所有文章列表代码实例
2017/12/28 Python
更新修改后的Python模块方法
2019/03/03 Python
Python使用for生成列表实现过程解析
2020/09/22 Python
荟萃全球保健品:维他购
2018/05/09 全球购物
草莓网官网:StrawberryNET
2019/08/21 全球购物
零件设计自荐信范文
2013/11/27 职场文书
元旦晚会上单位领导演讲稿
2014/01/05 职场文书
大学生开西餐厅创业计划书
2014/02/01 职场文书
专业求职信撰写要诀
2014/02/18 职场文书
高校优秀辅导员事迹材料
2014/05/07 职场文书
客运企业隐患排查工作方案
2014/06/06 职场文书
世博会口号
2014/06/20 职场文书
小学生安全教育主题班会
2015/08/12 职场文书
2016重阳节红领巾广播稿
2015/12/18 职场文书