- 效果 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; } } }
```// 自定义日历范围选择组件(倒数的时间段) sunxc 2018.12.15;(function($) {var calendarRange = (function() {/*** 插件函数* @param {dom} element 插件追加dom容器对象* @param {object} options 插件配置对象**/function calendarRange(element, options) {// calendar容器domthis.element = element// 合并插件配置 defaults + optionsthis.options = $.extend(true, $.fn.calendarRange.defaults, options || {})// 插件初始化this.init()}calendarRange.prototype = {init: function() {// 初始化插件 dom + 事件var me = this// 展示月的个数 强制转换为 12 避免出现 bugme.manyMonths = me.options.manyMonths > 12 ? 12 : me.options.manyMonths// 确定按钮me.calendarConfirmBtn = me.options.calendarConfirmBtn// 重置按钮me.calendarResetBtn = me.options.calendarResetBtn// dom// 开始var html = `<div class="calendar-range" id="calendarDom"><input id="calendarStartDate" type="hidden" value=""/><input id="calendarEndDate" type="hidden" value=""/><div class="calendar-week"><div class="week-text color-blue">日</div><div class="week-text">一</div><div class="week-text">二</div><div class="week-text">三</div><div class="week-text">四</div><div class="week-text">五</div><div class="week-text color-blue">六</div></div><div class="calendar-scroll"><div class="scroll-content clearfix">`// 日期拼接/*** 生成日期 html* @param {number || string} manyMonths 月份的个数*/function creationDateList(manyMonths) {let htmlStr = ''var now = me.options.calendarStartDate? new Date(me.options.calendarStartDate): new Date()// 当前的年 月var year = now.getFullYear()var month = now.getMonth() + 1// 根据月的数量循环生成 htmlfor (let i = 0; i < me.manyMonths; i++) {// 如果是只要一个月的数据便不做过多的加减判断if (me.manyMonths != 1) {// 非首次循环自加1,否则得出需要展示的最小的月份,正排if (i != 0) {month++// 判断月份转换年和月if (month < 1) {month = month - i + 12 + 1month = month > 12 ? 12 : monthyear -= 1} else if (month > 12) {month -= 12month = month === 0 ? 1 : monthyear++}} else {month -= me.manyMonths - 1// 判断月份转换年和月if (month < 1) {month += 12month = month > 12 ? 12 : monthyear--} else if (month > 12) {month -= 12month = month === 0 ? 1 : monthyear++}}}// 月份数组let monthsArray = nullif (me._isLeapYear(year)) {monthsArray = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31]} else {monthsArray = [31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31]}htmlStr += `<div class="content-title">${year}年${month}月</div>`for (let x = 0; x < monthsArray[month - 1]; x++) {let week = new Date(`${year}/${month}/${x + 1}`).getDay()// 月份首日判断:是周几就 margin-left 几个 content-item 的距离if (x === 0) {htmlStr += `<div class="content-item ${week === 0 || week === 6 ? 'color-blue' : ''}" data-date="${year}/${month}/${x +1}" style="margin-left:${(100 / 7) * week}%;">${x + 1}</div>`} else {htmlStr += `<div class="content-item ${week === 0 || week === 6 ? 'color-blue' : ''}" data-date="${year}/${month}/${x + 1}">${x + 1}</div>`}}}return htmlStr}html += creationDateList(me.manyMonths)// 结束html += `</div></div><div class="calendar-btn"><div class="reset-btn" id="calendarResetBtn">重置</div><div class="confirm-btn" id="calendarConfirmBtn">确定</div></div></div>`me.element.append(html)// 日期点击事件$('body').on('click', '#calendarDom .content-item', function(e) {me._clickHandle(e)})// 重置 按钮点击事件$('body').on('click', '#calendarResetBtn', function() {me._resetTimeData()})// 确定 按钮点击事件// $start, $end$('body').on('click', '#calendarConfirmBtn', function() {const $start = $('#calendarStartDate').val()const $end = $('#calendarEndDate').val()if ($start && $end) {// 提交数据事件me.options.callback($start, $end)}})},/**** @param {number} year 是否是闰年*/_isLeapYear: function(year) {return year % 4 == 0 && (year % 100 != 0 || year % 400 == 0)},/*** 每个小日期的点击事件* @param {object} e 点击的 dom 元素*/_clickHandle: function(e) {const me = thisconst $this = $(e.target)const index = $this.index()const $calendarStartDate = $('#calendarStartDate')const $calendarEndDate = $('#calendarEndDate')// 已经点击了两次if ($calendarStartDate.val() && $calendarEndDate.val()) {// 清空数据重新执行me._resetTimeData()me._clickHandle(e)} else if ($calendarStartDate.val()) {// 之前已经点击了一次开始const startIndex = $('#calendarDom').find('.content-item-start').index()// 判断当前的索引值如果小于之前点击的索引值,将当前点击的重置为开始点击的if (index < startIndex) {$this.addClass('content-item-start').siblings().removeClass('content-item-start')$calendarStartDate.val($this.attr('data-date'))} else {$this.addClass('content-item-end')$calendarEndDate.val($this.attr('data-date'))}} else {//从未点击过$this.addClass('content-item-start')$calendarStartDate.val($this.attr('data-date'))}},/*** 重置数据事件* @param {object} $this 点击的 dom 元素*/_resetTimeData: function($this) {$this = $this || $('#calendarDom .content-item')const $calendarStartDate = $('#calendarStartDate')const $calendarEndDate = $('#calendarEndDate')$calendarStartDate.val('')$calendarEndDate.val('')$this.siblings().removeClass('content-item-start').removeClass('content-item-end')}}return calendarRange})()$.fn.calendarRange = function(options) {return this.each(function() {var me = $(this)// 获取实例var instance = me.data('calendarRange')// 判断:实例如果未创建,创建实例if (!instance) {me.data('calendarRange', (instance = new calendarRange(me, options)))}if ($.type(options) === 'string') return instance[options]()})}$.fn.calendarRange.defaults = {// 指定开始的日期 yyyy/mm/ddcalendarStartDate: '',//展示的之前月份个数 默认为 3,最大为 12,大于 12 会强制转换为 12 避免出现 bugmanyMonths: 3,/*** 回调函数 主要是为了提交数据用的* @param {date} $start 开始时间* @param {date} $end 结束时间*/callback: function($start, $end) {console.log($start, $end)}}})($)// // 测试语法// $('#id1').calendarRange({// calendarStartDate: '2008/2/2',// manyMonths: 12,// callback: function($start,$end) {// console.log(`start:${$start}\nend:${$end}`)// }// })
- 使用方法
`` // 示例代码 // 测试语法 可配置的 options 参数,不写便是默认的 $('#id1').calendarRange({ calendarStartDate: '2008/2/2', manyMonths: 20, callback: function($start,$end) { console.log(start:${$start}\nend:${$end}`) } })
```

