- 效果 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容器dom
this.element = element
// 合并插件配置 defaults + options
this.options = $.extend(true, $.fn.calendarRange.defaults, options || {})
// 插件初始化
this.init()
}
calendarRange.prototype = {
init: function() {
// 初始化插件 dom + 事件
var me = this
// 展示月的个数 强制转换为 12 避免出现 bug
me.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
// 根据月的数量循环生成 html
for (let i = 0; i < me.manyMonths; i++) {
// 如果是只要一个月的数据便不做过多的加减判断
if (me.manyMonths != 1) {
// 非首次循环自加1,否则得出需要展示的最小的月份,正排
if (i != 0) {
month++
// 判断月份转换年和月
if (month < 1) {
month = month - i + 12 + 1
month = month > 12 ? 12 : month
year -= 1
} else if (month > 12) {
month -= 12
month = month === 0 ? 1 : month
year++
}
} else {
month -= me.manyMonths - 1
// 判断月份转换年和月
if (month < 1) {
month += 12
month = month > 12 ? 12 : month
year--
} else if (month > 12) {
month -= 12
month = month === 0 ? 1 : month
year++
}
}
}
// 月份数组
let monthsArray = null
if (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 = this
const $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/dd
calendarStartDate: '',
//展示的之前月份个数 默认为 3,最大为 12,大于 12 会强制转换为 12 避免出现 bug
manyMonths: 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}`) } })
```