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 相关文章推荐
extjs 学习笔记(二) Ext.Element类
Oct 13 Javascript
关于Javascript模块化和命名空间管理的问题说明
Dec 06 Javascript
js实现网页标题栏闪烁提示效果实例分析
Nov 20 Javascript
基于JavaScript实现div层跟随滚动条滑动
Jan 12 Javascript
javascript实现滚动效果的数字时钟实例
Jul 21 Javascript
jQuery插件Validation快速完成表单验证的方式
Jul 28 Javascript
遍历json获得数据的几种方法小结
Jan 21 Javascript
微信小程序 下拉菜单的实现
Apr 06 Javascript
ES6新特性五:Set与Map的数据结构实例分析
Apr 21 Javascript
jQuery实现注册会员时密码强度提示信息功能示例
Sep 05 jQuery
jQuery实现评论模块
Aug 19 jQuery
微信小程序实现首页弹出广告
Dec 03 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
dedecms系统常用术语汇总
2007/04/03 PHP
BOOM vs RR BO5 第二场 2.14
2021/03/10 DOTA
不懂JavaScript应该怎样学
2008/04/16 Javascript
javascript引导程序
2008/10/26 Javascript
javascript 获取url参数和script标签中获取url参数函数代码
2010/01/22 Javascript
Jquery.LazyLoad.js修正版下载,实现图片延迟加载插件
2011/03/12 Javascript
location.href用法总结(最主要的)
2013/12/27 Javascript
jQuery焦点控制图层展示延迟隐藏的方法
2015/03/09 Javascript
javascript判断css3动画结束 css3动画结束的回调函数
2015/03/10 Javascript
jquery实现标签支持图文排列带上下箭头按钮的选项卡
2015/03/14 Javascript
jQuery实现进度条效果代码
2015/12/17 Javascript
JavaScript对象参数的引用传递
2016/01/14 Javascript
Bootstrap布局组件应用实例讲解
2016/02/17 Javascript
node.js 中间件express-session使用详解
2017/05/20 Javascript
详解在Angular项目中添加插件ng-bootstrap
2017/07/04 Javascript
Angular4开发解决跨域问题详解
2017/08/28 Javascript
浅谈Node.js CVE-2017-14849 漏洞分析(详细步骤)
2017/11/10 Javascript
[原创]js实现保存文本框内容为本地文件兼容IE,chrome,火狐浏览器
2018/02/14 Javascript
详解angularjs跨页面传参遇到的一些问题
2018/11/01 Javascript
javascript 模块依赖管理的本质深入详解
2020/04/30 Javascript
VSCode 配置uni-app的方法
2020/07/11 Javascript
python实现巡检系统(solaris)示例
2014/04/02 Python
python抓取网页图片并放到指定文件夹
2014/04/24 Python
Python 专题二 条件语句和循环语句的基础知识
2017/03/19 Python
Django中信号signals的简单使用方法
2019/07/04 Python
Python Django 简单分页的实现代码解析
2019/08/21 Python
Python 处理日期时间的Arrow库使用
2020/08/18 Python
HTML文本属性&amp;颜色控制属性的实现
2019/12/17 HTML / CSS
eVitamins日本:在线购买折扣维生素、补品和草药
2019/04/04 全球购物
香港演唱会订票网站:StubHub香港
2019/10/10 全球购物
促销活动总结
2014/04/28 职场文书
个人工作表现评语
2014/04/30 职场文书
学雷锋标语
2014/06/25 职场文书
宣传部部长竞选稿
2015/11/21 职场文书
百年校庆宣传标语口号
2015/12/26 职场文书
python如何做代码性能分析
2021/04/26 Python