• 效果 Gif 图

    calendarRange 日历范围选择插件.gif

    • 源码 ``` // layout.less /375px布局/ /配合 js 计算的 rem 使用具体换算设计稿的 20px = 20 / @layremvalue/ @layremvalue: 100rem;
    • { margin: 0; padding: 0; box-sizing: border-box; } html { font-size: calc(100vw / 7.5); } body { font-size: 0.28rem; font-family: ‘Helvetica Neue’, Helvetica, Arial, ‘PingFang SC’, ‘Hiragino Sans GB’, ‘Heiti SC’, ‘Microsoft YaHei’, ‘WenQuanYi Micro Hei’, sans-serif; -webkit-text-size-adjust: none; -moz-text-size-adjust: none; -ms-text-size-adjust: none; text-size-adjust: none; padding: 0; margin: 0 auto; -webkit-tap-highlight-color: rgba(0, 0, 0, 0); / 取消链接高亮 / background-color: #f1f5fb; } h1, h2, h3, h4, h5 { font-weight: normal; } a { text-decoration: none; color: inherit; } // 公用容器 .mainbox { padding-bottom: 98 / @layremvalue; overflow-y: auto; } /文本单行溢出隐藏/ .txtoneline { overflow: hidden; white-space: nowrap; text-overflow: ellipsis; } /文本多行溢出隐藏 -webkit-line-clamp: 2; 溢出行数/ .txtmorline { display: -webkit-box; -webkit-box-orient: vertical; overflow: hidden; text-overflow: ellipsis; } /表单元素统一初始化样式/ input, select, button { -webkit-appearance: none; /去除阴影/ border: 0; outline: 0; background-color: transparent; } .checkbox { -webkit-appearance: checkbox; } input[type=’checkbox’] { -webkit-appearance: checkbox; }

    /input palceholder 样式自定义/ / 使用webkit内核的浏览器 / input::-webkit-input-placeholder, textarea::-webkit-input-placeholder { color: #999; } / Firefox版本4-18 / input::-moz-placeholder, textarea::-webkit-input-placeholder { color: #999; } / Firefox版本19+ / input:-ms-input-placeholder, textarea::-webkit-input-placeholder { color: #999; } /清除浮动/ .clearfix:after { content: ‘ ‘; display: block; height: 0; clear: both; } .clearfix { zoom: 1; } /IE6/7/ / 弹窗专用 禁止滚轮 滚动*/ .scrollnone { width: 100%; height: 100%; overflow: hidden; position: fixed; max-width: 640px; min-width: 320px; left: 0; right: 0; margin: auto; } // link 右箭头 .link-arrow-right { position: relative; &::before { content: ‘’; display: block; position: absolute; right: 0; top: 0; bottom: 0; margin: auto; background: url(../img/sales/icon-rightarrow.png) center center no-repeat; width: 18 / @layremvalue; height: 30 /@layremvalue; background-size: 18 / @layremvalue 30 /@layremvalue; } }

    // calendarRange.less @import ‘/css/layout.css’; /配合 js 计算的 rem 使用具体换算设计稿的 20px = 20 / @layremvalue/ @layremvalue: 100rem; // 日历范围插件样式表 @activeColor: #4289fe; @middleColor: #ecf3fe;

    [id*=’id’], [id^=’id’] { height: (48 + 725 + 88) / @layremvalue; } .calendar-range { text-align: center; color: #2e4052; font-size: 32 / @layremvalue; position: relative; background-color: #fff; max-height: (48 + 725 + 88) / @layremvalue; .color-blue { color: @activeColor; } .calendar-week { display: flex; height: 48 / @layremvalue; .week-text { font-size: 24 / @layremvalue; flex: 100 / 7; line-height: 48 / @layremvalue; background-color: #fafafa; } } .calendar-scroll { overflow-y: auto; max-height: 725/@layremvalue; .scroll-content { padding: 15 / @layremvalue 0 0; div { float: left; } .content-title { width: 100%; line-height: 50 / @layremvalue; height: 50 / @layremvalue; color: #000000; font-size: 32 / @layremvalue; } .content-item { width: 100 / 7%; height: 112 / @layremvalue; line-height: 50 / @layremvalue; padding: 6 / @layremvalue 0; transition: all .2s; &-start, &-end { background-color: @activeColor; color: #fff; border-radius: 8 / @layremvalue; position: relative; &::before { content: ‘’; display: block; position: absolute; left: 0; right: 0; bottom: 6 / @layremvalue; font-size: 24 / @layremvalue; } } &-start { &::before { content: ‘开始’; } } &-end { &::before { content: ‘结束’; } } &-middle { background-color: @middleColor; } } } } .calendar-btn { height: 88 / @layremvalue; line-height: 88 / @layremvalue; display: flex; justify-content: center; box-shadow: 0 1px 0 0 #ddd inset; div { flex: 50%; } .reset-btn { color: #2e4052; } .confirm-btn { color: #fff; background-color: @activeColor; } } }

    1. ```
    2. // 自定义日历范围选择组件(倒数的时间段) sunxc 2018.12.15
    3. ;(function($) {
    4. var calendarRange = (function() {
    5. /**
    6. * 插件函数
    7. * @param {dom} element 插件追加dom容器对象
    8. * @param {object} options 插件配置对象
    9. *
    10. */
    11. function calendarRange(element, options) {
    12. // calendar容器dom
    13. this.element = element
    14. // 合并插件配置 defaults + options
    15. this.options = $.extend(true, $.fn.calendarRange.defaults, options || {})
    16. // 插件初始化
    17. this.init()
    18. }
    19. calendarRange.prototype = {
    20. init: function() {
    21. // 初始化插件 dom + 事件
    22. var me = this
    23. // 展示月的个数 强制转换为 12 避免出现 bug
    24. me.manyMonths = me.options.manyMonths > 12 ? 12 : me.options.manyMonths
    25. // 确定按钮
    26. me.calendarConfirmBtn = me.options.calendarConfirmBtn
    27. // 重置按钮
    28. me.calendarResetBtn = me.options.calendarResetBtn
    29. // dom
    30. // 开始
    31. var html = `<div class="calendar-range" id="calendarDom">
    32. <input id="calendarStartDate" type="hidden" value=""/>
    33. <input id="calendarEndDate" type="hidden" value=""/>
    34. <div class="calendar-week">
    35. <div class="week-text color-blue">日</div>
    36. <div class="week-text">一</div>
    37. <div class="week-text">二</div>
    38. <div class="week-text">三</div>
    39. <div class="week-text">四</div>
    40. <div class="week-text">五</div>
    41. <div class="week-text color-blue">六</div>
    42. </div>
    43. <div class="calendar-scroll">
    44. <div class="scroll-content clearfix">`
    45. // 日期拼接
    46. /**
    47. * 生成日期 html
    48. * @param {number || string} manyMonths 月份的个数
    49. */
    50. function creationDateList(manyMonths) {
    51. let htmlStr = ''
    52. var now = me.options.calendarStartDate
    53. ? new Date(me.options.calendarStartDate)
    54. : new Date()
    55. // 当前的年 月
    56. var year = now.getFullYear()
    57. var month = now.getMonth() + 1
    58. // 根据月的数量循环生成 html
    59. for (let i = 0; i < me.manyMonths; i++) {
    60. // 如果是只要一个月的数据便不做过多的加减判断
    61. if (me.manyMonths != 1) {
    62. // 非首次循环自加1,否则得出需要展示的最小的月份,正排
    63. if (i != 0) {
    64. month++
    65. // 判断月份转换年和月
    66. if (month < 1) {
    67. month = month - i + 12 + 1
    68. month = month > 12 ? 12 : month
    69. year -= 1
    70. } else if (month > 12) {
    71. month -= 12
    72. month = month === 0 ? 1 : month
    73. year++
    74. }
    75. } else {
    76. month -= me.manyMonths - 1
    77. // 判断月份转换年和月
    78. if (month < 1) {
    79. month += 12
    80. month = month > 12 ? 12 : month
    81. year--
    82. } else if (month > 12) {
    83. month -= 12
    84. month = month === 0 ? 1 : month
    85. year++
    86. }
    87. }
    88. }
    89. // 月份数组
    90. let monthsArray = null
    91. if (me._isLeapYear(year)) {
    92. monthsArray = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31]
    93. } else {
    94. monthsArray = [31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31]
    95. }
    96. htmlStr += `<div class="content-title">${year}年${month}月</div>`
    97. for (let x = 0; x < monthsArray[month - 1]; x++) {
    98. let week = new Date(`${year}/${month}/${x + 1}`).getDay()
    99. // 月份首日判断:是周几就 margin-left 几个 content-item 的距离
    100. if (x === 0) {
    101. htmlStr += `<div class="content-item ${
    102. week === 0 || week === 6 ? 'color-blue' : ''
    103. }" data-date="${year}/${month}/${x +
    104. 1}" style="margin-left:${(100 / 7) * week}%;">${x + 1}</div>`
    105. } else {
    106. htmlStr += `<div class="content-item ${
    107. week === 0 || week === 6 ? 'color-blue' : ''
    108. }" data-date="${year}/${month}/${x + 1}">${x + 1}</div>`
    109. }
    110. }
    111. }
    112. return htmlStr
    113. }
    114. html += creationDateList(me.manyMonths)
    115. // 结束
    116. html += `</div>
    117. </div>
    118. <div class="calendar-btn">
    119. <div class="reset-btn" id="calendarResetBtn">重置</div>
    120. <div class="confirm-btn" id="calendarConfirmBtn">确定</div>
    121. </div>
    122. </div>`
    123. me.element.append(html)
    124. // 日期点击事件
    125. $('body').on('click', '#calendarDom .content-item', function(e) {
    126. me._clickHandle(e)
    127. })
    128. // 重置 按钮点击事件
    129. $('body').on('click', '#calendarResetBtn', function() {
    130. me._resetTimeData()
    131. })
    132. // 确定 按钮点击事件
    133. // $start, $end
    134. $('body').on('click', '#calendarConfirmBtn', function() {
    135. const $start = $('#calendarStartDate').val()
    136. const $end = $('#calendarEndDate').val()
    137. if ($start && $end) {
    138. // 提交数据事件
    139. me.options.callback($start, $end)
    140. }
    141. })
    142. },
    143. /**
    144. *
    145. * @param {number} year 是否是闰年
    146. */
    147. _isLeapYear: function(year) {
    148. return year % 4 == 0 && (year % 100 != 0 || year % 400 == 0)
    149. },
    150. /**
    151. * 每个小日期的点击事件
    152. * @param {object} e 点击的 dom 元素
    153. */
    154. _clickHandle: function(e) {
    155. const me = this
    156. const $this = $(e.target)
    157. const index = $this.index()
    158. const $calendarStartDate = $('#calendarStartDate')
    159. const $calendarEndDate = $('#calendarEndDate')
    160. // 已经点击了两次
    161. if ($calendarStartDate.val() && $calendarEndDate.val()) {
    162. // 清空数据重新执行
    163. me._resetTimeData()
    164. me._clickHandle(e)
    165. } else if ($calendarStartDate.val()) {
    166. // 之前已经点击了一次开始
    167. const startIndex = $('#calendarDom')
    168. .find('.content-item-start')
    169. .index()
    170. // 判断当前的索引值如果小于之前点击的索引值,将当前点击的重置为开始点击的
    171. if (index < startIndex) {
    172. $this
    173. .addClass('content-item-start')
    174. .siblings()
    175. .removeClass('content-item-start')
    176. $calendarStartDate.val($this.attr('data-date'))
    177. } else {
    178. $this.addClass('content-item-end')
    179. $calendarEndDate.val($this.attr('data-date'))
    180. }
    181. } else {
    182. //从未点击过
    183. $this.addClass('content-item-start')
    184. $calendarStartDate.val($this.attr('data-date'))
    185. }
    186. },
    187. /**
    188. * 重置数据事件
    189. * @param {object} $this 点击的 dom 元素
    190. */
    191. _resetTimeData: function($this) {
    192. $this = $this || $('#calendarDom .content-item')
    193. const $calendarStartDate = $('#calendarStartDate')
    194. const $calendarEndDate = $('#calendarEndDate')
    195. $calendarStartDate.val('')
    196. $calendarEndDate.val('')
    197. $this
    198. .siblings()
    199. .removeClass('content-item-start')
    200. .removeClass('content-item-end')
    201. }
    202. }
    203. return calendarRange
    204. })()
    205. $.fn.calendarRange = function(options) {
    206. return this.each(function() {
    207. var me = $(this)
    208. // 获取实例
    209. var instance = me.data('calendarRange')
    210. // 判断:实例如果未创建,创建实例
    211. if (!instance) {
    212. me.data('calendarRange', (instance = new calendarRange(me, options)))
    213. }
    214. if ($.type(options) === 'string') return instance[options]()
    215. })
    216. }
    217. $.fn.calendarRange.defaults = {
    218. // 指定开始的日期 yyyy/mm/dd
    219. calendarStartDate: '',
    220. //展示的之前月份个数 默认为 3,最大为 12,大于 12 会强制转换为 12 避免出现 bug
    221. manyMonths: 3,
    222. /**
    223. * 回调函数 主要是为了提交数据用的
    224. * @param {date} $start 开始时间
    225. * @param {date} $end 结束时间
    226. */
    227. callback: function($start, $end) {
    228. console.log($start, $end)
    229. }
    230. }
    231. })($)
    232. // // 测试语法
    233. // $('#id1').calendarRange({
    234. // calendarStartDate: '2008/2/2',
    235. // manyMonths: 12,
    236. // callback: function($start,$end) {
    237. // console.log(`start${$start}\nend${$end}`)
    238. // }
    239. // })
    • 使用方法 `` // 示例代码 // 测试语法 可配置的 options 参数,不写便是默认的 $('#id1').calendarRange({ calendarStartDate: '2008/2/2', manyMonths: 20, callback: function($start,$end) { console.log(start:${$start}\nend:${$end}`) } })

    ```