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的trim,ltrim,rtrim自定义函数
Sep 21 Javascript
浅说js变量
May 25 Javascript
Lazy Load 延迟加载图片的jQuery插件中文使用文档
Oct 18 Javascript
Jquery-1.9.1源码分析系列(十一)之DOM操作
Nov 25 Javascript
理解Javascript的call、apply
Dec 16 Javascript
Bootstrap + AngularJS 实现简单的数据过滤字符查找功能
Jul 27 Javascript
JS实现快速比较两个字符串中包含有相同数字的方法
Sep 11 Javascript
node.js 基于cheerio的爬虫工具的实现(需要登录权限的爬虫工具)
Apr 10 Javascript
微信小程序实现同一页面取值的方法分析
Apr 30 Javascript
vue 中几种传值方法(3种)
Nov 12 Javascript
vue 解决uglifyjs-webpack-plugin打包出现报错的问题
Aug 04 Javascript
vue点击按钮实现简单页面的切换
Sep 08 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安装memcached扩展笔记
2015/05/28 PHP
php实现无限级分类查询(递归、非递归)
2016/03/10 PHP
php mongodb操作类 带几个简单的例子
2016/08/25 PHP
laravel-admin 实现在指定的相册下添加照片
2019/10/21 PHP
TopList标签和JavaScript结合两例
2007/08/12 Javascript
javascript CSS画图之基础篇
2009/07/29 Javascript
jQuery get和post 方法传值注意事项
2009/11/03 Javascript
在Python中使用glob模块查找文件路径的方法
2015/06/17 Javascript
JS实现带提示的星级评分效果完整实例
2015/10/30 Javascript
原生JS实现平滑回到顶部组件
2016/03/16 Javascript
js实现砖头在页面拖拉效果
2020/11/20 Javascript
开源免费天气预报接口API及全国所有地区代码(国家气象局提供)
2016/12/26 Javascript
在node中如何使用 ES6
2017/04/22 Javascript
基于LayUI分页和LayUI laypage分页的使用示例
2017/08/02 Javascript
EasyUI Tree树组件无限循环的解决方法
2017/09/27 Javascript
详解React中setState回调函数
2018/06/14 Javascript
vue刷新页面时去闪烁提升用户体验效果的实现方法
2018/12/10 Javascript
Vue程序化的事件监听器(实例方案详解)
2020/01/07 Javascript
JavaScript 异步时序问题
2020/11/20 Javascript
原生js+canvas实现验证码
2020/11/29 Javascript
python self,cls,decorator的理解
2009/07/13 Python
python 实现插入排序算法
2012/06/05 Python
Django admin实现图书管理系统菜鸟级教程完整实例
2017/12/12 Python
Python实现发送与接收邮件的方法详解
2018/03/28 Python
对Xpath 获取子标签下所有文本的方法详解
2019/01/02 Python
python3 tkinter实现点击一个按钮跳出另一个窗口的方法
2019/06/13 Python
对Python中class和instance以及self的用法详解
2019/06/26 Python
Pandas 解决dataframe的一列进行向下顺移问题
2019/12/27 Python
FC-Moto瑞典:欧洲最大的摩托车服装和头盔商店之一
2018/11/27 全球购物
文职个人求职信范文
2013/09/23 职场文书
幼儿园保教管理制度
2014/02/03 职场文书
2014年幼儿园元旦活动方案
2014/02/13 职场文书
学校献爱心活动总结
2014/07/08 职场文书
合同意向书范本
2014/07/30 职场文书
佛光寺导游词
2015/02/10 职场文书
求职导师推荐信范文
2015/03/27 职场文书