整合营销服务商

电脑端+手机端+微信端=数据同步管理

免费咨询热线:

手把手教你用vue 编写一个日历组件「实践」

手把手教你用vue 编写一个日历组件「实践」

信有不少小伙伴和我一样一提到日历就脑壳疼,然后去网上搜索好用的日历组件,如element-ui什么的,但是日历毕竟是别人开发出来的, 和自己家ui设计出来的功能样式毕竟不能100%相似,所以这个时候要么就去git上找一个相似的然后去修改代码,要么就只能自己开发一个了,所以我也是把我自己学到的日历组件封装思路分享给大家;

虽然我知道日历组件肯定已经有很多人发过文章,写过思路了,但是我还是想写一下。

准备工作

我是选择弄一个新的脚手架去开发,所以我是去vue-cli官网去拉取一个新的脚手架在本地,相信这个大家应该都会。 拉取成功之后npm serve 启动;

image.png

然后我习惯一点用less写css样式,所以我在装一个less和less-loader,然后这个因人而异;

开始

image.png

相信很多小伙伴和我一样看到日历之后不知道怎么下手,如何能区分上下月和当前月呢,其实明白思路和原理之后就很简单。

一个日历有的是42天有的是35天,原因是6行或7行,7行展示的就比较全面;42天的优点是能全部展示出上个月,当前月以及下个月,缺点是上个月和下个月占比较多,有些冗余,如果是35天看起来就会比较精简,但有的月份就不能全部展示出来还是需要42天,这个也无伤大雅,我们就以42天为例;

首先我们需要看当前月的第一天是周几,5月的1号就是周三,那么就用42 - 2(这里注意如果是周日在第一个就是42 - 周几,如果是周一在第一个就是42 - (周几 - 1 )剩下的就是当前月和下个月的日期了。

我创建一个公共js里面放一些公共的方法方便在组件中调用;公共的js我就叫utils.js;
getYearMonthDay 就是utils里面的一个公共方法,是为了方便获取年月日;
const getYearMonthDay=(date)=> {
 let year=date.getFullYear();
 let month=date.getMonth();
 let day=date.getDate();
 return {year, month, day};
};

computed: {
    visibleCalendar: function () {
        let calendatArr=[];
        先得到当前的年,月,日
        let {year, month, day}=utils.getNewDate(utils.getDate(this.time.year, this.time.month, 1));
        
        获取当月的第一天 得到2019-5-1
        let currentFirstDay=utils.getDate(year, month, 1);
        
        获取第一天是星期几 得到 3
        let weekDay=currentFirstDay.getDay();
        
        用当月的第一天减去 周几前面几天 这样就能得到上个月开始的天数 (当前月1号是周三,那么周一就是上个月的最后两天)
        let startTime=currentFirstDay - (weekDay - 1) * 24 * 60 * 60 * 1000;
        
        然后得到所有的日期
        for (let i=0; i < 42; i++) {
          calendatArr.push({
            date: new Date(startTime + i * 24 * 60 * 60 * 1000),
            year: year,
            month: month + 1,
            day: new Date(startTime + i * 24 * 60 * 60 * 1000).getDate()
          })
        };
        return calendatArr
    }
}

然后dom结构去v-for这个数组,这样就能得到一个初始的日历了

image.png


但是这样很丑,而且不能区分出哪一天是上个月哪一天是下个月,所以我们需要给上下月去加一下样式来区分当前月和上下月的区分

<ul class="calendar-view clear">
  <li v-for="(item, index) in visibleCalendar" 
    :key="index" 
    class="date-view"
    :class="[
      {'notCurrentMonth-class': !isCurrentMonth(item.date)},
      {currentDay: isCurrentDay(item.date)},
    ]"
    @click="handleClickDay(item, index)"
  >
    <span class="date-day" >
      {{item.day}}
    </span>
  </li>
</ul>
notCurrentMonth-class 是区分上下月的类名
currentDay 是判断是否是今天的类名

判断是否是当前月的方法,传入每一天 用传入的每一天去和当前年月做比较然后返回
isCurrentMonth (date) {
    let {year: currentYear, month: currentMonth}=utils.getYearMonthDay(utils.getDate(this.time.year, this.time.month, 1));
    let {year, month}=utils.getYearMonthDay(date);
    return currentYear==year && currentMonth==month
}
判断是否是当前天的方法 同理
isCurrentDay (date) {
    let {year: currentYear, month: currentMonth, day: currentDay}=utils.getYearMonthDay(new Date());
    let {year, month, day}=utils.getYearMonthDay(date);
    return currentYear==year && currentMonth==month && currentDay==day;
}

然后给类名加一些自己喜欢的样式就可以愉快的区分出当前月和上下月以及今天

image.png

现在就差左右切换和点击今天回到当前月了,接下来就很简单,我们先写两个方法用来切换上下月

先去utils里面创建一个新的方法用来获取当前几月几日
const getDate=(year, month, day)=> {
  return new Date(year, month, day);
}
在data () {
    let {year, month, day}=utils.getYearMonthDay(new Date());
    return {
        yearMonth: {year, month, day}, 
    }
}
// 上一个月 获取当年月 用setMonth()去设置月份,然后更新yearMonth
  handlePrevMonth () {
    let prevMonth=utils.getDate(this.yearMonth.year,this.yearMonth.month,1);
    prevMonth.setMonth(prevMonth.getMonth() - 1);
    this.yearMonth=utils.getYearMonthDay(prevMonth);
  }
  // 下一个月 获取当年月 用setMonth()去设置月份,然后更新yearMonth
  handleNextMonth () {
    let nextMonth=utils.getDate(this.yearMonth.year,this.yearMonth.month,1); 
    nextMonth.setMonth(nextMonth.getMonth() + 1);
    this.yearMonth=utils.getYearMonthDay(nextMonth);
  }
  // 点击回到今天 同理
  handleToday () {
    this.yearMonth=utils.getYearMonthDay(new Date());
  }

就这样一个左右切换以及点击回到今天的日历就完成了,是不是非常非常的简单?

gitHub 日历地址:https://github.com/xiangnideye/vue-date-picker

我把详细的代码上传到了我的gitHub上面,在git上面我写的更详细一些,也提供了一些对外的点击事件,这样在组件的外面可以调用里面的一些方法,这样用起来更方便,如果你觉得还不错,可以去git上面给个星星或者是啥的,感谢大家支持,如果有说的不对的地方,欢迎指出,共同探讨!


作者:Alawaysonl_c839
链接:https://www.jianshu.com/p/d8ce25e9badb

datefns为浏览器中操作JavaScript日期提供了最全面、最简单、最一致的工具集,并且可以在node.js中使用!常见的类似的库还有moment.js和day.js!





Github

https://github.com/date-fns/date-fns

特性

  • 模块化

只是用需要使用的功能,可以很好地与webpack, Browserify, 或者 Rollup集成

  • 原生日期

date-fns不会重新造轮子,而是使用现有的本机类型。此外,出于安全考虑,它不会扩展核心对象。date-fns中的函数可以正常工作,在某些情况下会遵循ECMAScript行为。

  • 纯函数

date-fns是使用纯函数构建的,并且始终返回新的日期实例,而不是更改传递的实例。这有助于防止错误并避免长时间的调试会话。

  • 支持Typescript和Flow

date-fns支持FlowTypeScript

  • 国际化

支持几十种语言,当然包括了简体中文,只有当你需要使用的时候才会包括进来

  • 一致性

它总是返回同一时区中的日期,不管传递的是时间戳、字符串还是日期对象。该API经过定制,具有可预测的名称和参数顺序。

  • 可靠性

datefns尊重时区和夏时制。它遵循语义版本控制,因此始终向后兼容。每个构建CI在大约400个时区检查超过650000个示例

  • 简单

最好的API是不存在API。对于date fns,你总是有一个函数可以做一件事。并且总是有一个单一的方法来解决问题。

  • 性能好

除了体积小之外,date-fns速度很快。

  • 详细的文档

每个函数都有一个详细的例子说明。由于JSDoc注释,文档可以在线(在网站上)和离线访问。




示例

  • 格式化
import { format, formatDistance, formatRelative, subDays } from 'date-fns'

format(new Date(), "'Today is a' iiii")
//=> "Today is a Thursday"

formatDistance(subDays(new Date(), 3), new Date())
//=> "3 days ago"

formatRelative(subDays(new Date(), 3), new Date())
//=> "last Friday at 7:26 p.m."
  • 国际化
import { formatRelative, subDays } from 'date-fns'
import { es, ru } from 'date-fns/locale'

formatRelative(subDays(new Date(), 3), new Date())
//=> "last Friday at 7:26 p.m."

formatRelative(subDays(new Date(), 3), new Date(), { locale: es })
//=> "el viernes pasado a las 19:26"

formatRelative(subDays(new Date(), 3), new Date(), { locale: ru })
//=> "в прошлую пятницу в 19:26"
  • 日常使用
import { addYears, formatWithOptions, toUpper } from 'date-fns/fp'
import { eo } from 'date-fns/locale'

const addFiveYears=addYears(5)

const dateToString=formatWithOptions({ locale: eo }, 'D MMMM YYYY')

const dates=[
  new Date(2017, 0, 1),
  new Date(2017, 1, 11),
  new Date(2017, 6, 2)
]

const toUpper=arg=> String(arg).toUpperCase()

const formattedDates=dates.map(addFiveYears).map(dateToString).map(toUpper)
//=> ['1 JANUARO 2022', '11 FEBRUARO 2022', '2 JULIO 2022']

总结

不论是moment.js或者day.js亦或是datefns都是JavaScript中处理日期非常好的库,也避免了很多日期处理中的很多问题!

今每个人的事情都变的越来越多了,没有一个好的提醒工具,你会不会错过很多,比如:交房贷、追剧、看球等等,我们知道手机上的日历,时钟,都能提醒我们,可是作为程序员的我们,是不是也该尝试一下,弄一个日历处理?

首先明确,我们需要什么功能:通过日历来展示我们的待办事项?

如果从头写,是不是有点费时?这里,我们推荐一个jQuery插件:FullCalendar

我们先目的一下它的风采吧。

首先,FullCalendar最大的特点是,可以全日历上拖放的,比如:我5月19号添加的备忘,可以拖放到5月31号上。添加的备忘事件还可以跨好几天来拖放,真的很方便。

那么FullCalendar是什么?

严格的说,它是一个开源的,并可定制的JavaScript事件日历,支持全尺寸拖放。

这里有个比较重要的声明:它是一个很好的活动展示库,不是一个完整的事件管理解决方案,就是说不能修改活动事件的名称。你需要通过它的JS函数和配置等来设置。

那么如何获取它?

你可以通过github来搜索FullCalendar,它也有官网可以查看各种示例(当然也包括Google日历的Style)

那么它的兼容性如何?

它支持Firefox、Chrome、Safari、IE9+等所有现代浏览器。它依赖于jQuery 2.0.0+、Moment 2.9.0+(这是一个对日历和时间进行解析、验证、操作、显示的js库)

那么如何使用它呢?

通过上图的Head部分引用,Script,Html,就可以完成一个日历的展示了。

至此,这个开源的日历库就介绍完了,如果工作中有需要,它是个不错的选择。看文章累了吗?来张图片养养眼?(图片来源网络,如有侵权请告知。)

图片来自网络,如有侵权请告知,我们会尽快删除。谢谢。