适配移动端和PC的精准获取时间日期jquery.date.js的用法以及遇见的问题

介绍了一个用于移动项目的精准时间选择器插件jquery.date.js的使用与优化过程,解决了跨浏览器兼容性和触摸事件处理的问题。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

最近公司在做移动项目的过程中用到了精准的时间获取,找了很久决定用这个jquery.date.js包,因为很简单,引进去就能用很方便。不过在使用的过程中,不同的浏览器以及不同版本的手机都有一些反馈,找了一些资料解决了比较严重的BUG。

下图是效果图(获取日期时分):

效果图
获取日期时分

以下是修正过(第一个问题)的jquery.date.js的代码:

/*!
 * jquery.date.js v1.3.7
 * By 雾空 https://github.com/weijhfly/jqueryDatePlugin
 * Time:2017/1/24
*/
(function (factory) {
	if (typeof define === 'function' && define.amd) {
		// AMD
		define(['jquery'], factory);
	} else if (typeof exports === 'object') {
		// CommonJS
		factory(require('jquery'));
	} else {
		// Browser globals
		factory(jQuery);
	}
}(function ($) {
    'use strict';
 
    var d = new Date(),
        doc = window.document,
        nowYear = d.getFullYear(),
        nowMonth = d.getMonth() + 1,
        domDate,
        createDate,
		time,
        body = $('body'),
        emptyStr = "<li></li>",
        isTouch = "ontouchend" in doc,
        tstart = isTouch ? "touchstart" : "mousedown",
        tmove = isTouch ? "touchmove" : "mousemove",
        tend = isTouch ? "touchend" : "mouseup",
        tcancel = isTouch ? "touchcancel" : "mouseleave",
        isEnglish = (navigator.language || navigator.browserLanguage).toLowerCase().indexOf('zh') == -1,
		//基于40px的高度滑动,自适应就改动这或者dpr
		h = 40,
		dpr = $('html').attr('data-dpr') || 1,
		resH = h*dpr,
        //支持的时间格式展示
        dateFormat = [
			//年月日 时分秒
			['YYYY-MM-DD hh:mm:ss','YY-MM-DD hh:mm:ss','YYYY/MM/DD hh:mm:ss','YY/MM/DD hh:mm:ss'],
			//年月日 时分
			['YYYY-MM-DD hh:mm','YY-MM-DD hh:mm','YYYY/MM/DD hh:mm','YY/MM/DD hh:mm'],
			//年月日
			['YYYY-MM-DD','YY-MM-DD','YYYY/MM/DD','YY/MM/DD'],
			//年月
			['YYYY-MM','YY-MM','YYYY/MM','YY/MM']
        ],
    	
        opts = {            
            beginYear: 2010,        
            endYear: 2088, //可不填,结束年份不会小于当前年份           
            type:'YYYY-MM-DD',
            limitTime:false//限制选择时间 today 今天之前的时间不可选 tomorrow 明天之前的不可选
        };
    //dom渲染
    domDate = '<div id="date-wrapper"><h3>选择日期</h3><div id="d-content"><div id="d-tit"><div class="t1">年</div><div class="t2">月</div><div class="t3">日</div><div class="t4">时</div><div class="t5">分</div><div class="t6">秒</div></div><div id="d-bg"><ol id="d-year"></ol><ol id="d-month"></ol><ol id="d-day"></ol><ol id="d-hours"></ol><ol id="d-minutes"></ol><ol id="d-seconds"></ol></div></div><a id="d-cancel" href="javascript:">取消</a><a id="d-confirm" href="javascript:">确定</a></div><div id="d-mask"></div>';
    var css = '<style type="text/css">a{text-decoration:none;}ol,li{margin:0;padding:0}li{list-style-type:none}#date-wrapper{position:fixed;top:50%;left:50%;width:90%;margin: -139px 0 0 -45%;z-index:56;text-align:center;background:#fff;border-radius:3px;padding-bottom:15px;display:none}#d-mask{position:fixed;width:100%;height:100%;top:0;left:0;background:#000;filter:alpha(Opacity=50);-moz-opacity:.5;opacity:.5;z-index:55;display:none}#date-wrapper h3{line-height:50px;background:#d6aa7b;color:#fff;font-size:20px;margin:0;border-radius:3px 3px 0 0}#date-wrapper ol,#d-tit>div{width:16.6666666%;float:left;position:relative}#d-content{padding:10px}#d-content #d-bg{background:#f8f8f8;border-radius:0 0 5px 5px;height:120px;overflow:hidden;margin-bottom:10px;position:relative}#d-cancel,#d-confirm{border-radius:3px;float:left;width:40%;line-height:36px;font-size:16px;background:#eee;color:#a1a1a1;margin:0 5%}#d-confirm{background:#d6aa7b;color:#fff}#date-wrapper li{line-height:40px;height:40px;cursor:pointer;position:relative}#d-tit{background:#f8f8f8;overflow:hidden;border-radius:5px 5px 0 0;line-height:30px;margin-bottom:-1px}#date-wrapper ol{-webkit-overflow-scrolling:touch;position:absolute;top:0;left:0}#date-wrapper ol:nth-child(2){left:16.6666666%}#date-wrapper ol:nth-child(3){left:33.3333332%}#date-wrapper ol:nth-child(4){left:49.9999998%}#date-wrapper ol:nth-child(5){left:66.6666664%}#date-wrapper ol:nth-child(6){left:83.333333%}#d-content #d-bg:after{content:\'\';height:40px;background:#eee;position:absolute;top:40px;left:0;width:100%;z-index:1}#date-wrapper li span{position:absolute;width:100%;z-index:99;height:100%;left:0;top:0}#date-wrapper.two ol,.two #d-tit>div{width:50%}#date-wrapper.two ol:nth-child(2){left:50%}#date-wrapper.three ol,.three #d-tit>div{width:33.333333%}#date-wrapper.three ol:nth-child(2){left:33.333333%}#date-wrapper.three ol:nth-child(3){left:66.666666%}#date-wrapper.four ol,.four #d-tit>div{width:25%}#date-wrapper.four ol:nth-child(2){left:25%}#date-wrapper.four ol:nth-child(3){left:50%}#date-wrapper.four ol:nth-child(4){left:75%}#date-wrapper.five ol,.five #d-tit>div{width:20%}#date-wrapper.five ol:nth-child(2){left:20%}#date-wrapper.five ol:nth-child(3){left:40%}#date-wrapper.five ol:nth-child(4){left:60%}#date-wrapper.five ol:nth-child(5){left:80%}</style>';
	
	if(isEnglish){
		domDate = domDate.replace('选择日期','DatePicker').replace('取消','cancel').replace('确定','confirm');
		css = css.replace('</style>','#date-wrapper #d-tit{display:none;}</style>');
	}
	if(h != 40){
		css = css.replace('40px',h+'px');
	}
	if(dpr != 1){
		css = css.replace(/(\d+)px/g,function(i){
			return i.replace(/\D/g,'')*dpr + 'px';
		});
	}
    body.append(css).append(domDate);
    
    createDate = {
        y:function(begin,end){
            var domYear = '',
				end = end <= nowYear ? (end + 10) :end;
				
            for (var i = begin; i <= end; i++){domYear += '<li><span>' + i + '</span></li>';}
            $('#d-year').html(emptyStr + domYear + emptyStr);
        },
		m:function(){
			var domMonth = '';
			for (var j = 1; j <= 12; j++) {j = j<10?'0'+j:j;domMonth += '<li><span>' + j + '</span></li>';}
            $('#d-month').html(emptyStr + domMonth + emptyStr);
		},
		d:function(end,active){
			var end = end || createDate.bissextile(nowYear,nowMonth),
				domDay = '';
            for (var k = 1; k <= end; k++) {
				k = k<10?'0'+k:k;
				if(active && active == k){
					domDay += '<li class="active"><span>' + k + '</span></li>';
				}else{
					domDay += '<li><span>' + k + '</span></li>';
				}
			}
            $('#d-day').html(emptyStr + domDay + emptyStr);
		},
        hm:function(){
            var domHours = '',domMinutes = '';
			
            for (var i = 0; i <= 23; i++) {i = i<10?'0'+i:i;domHours += '<li><span>' + i + '</span></li>';}
            $('#d-hours').html(emptyStr + domHours + emptyStr);
            
            for (var j = 0; j <= 59; j++) {j = j<10?'0'+j:j;domMinutes += '<li><span>' + j + '</span></li>';}
            $('#d-minutes').html(emptyStr + domMinutes + emptyStr);
            
        },
        s:function(){
            var domSeconds = '';
			
            for (var i = 0; i <= 59; i++) {i = i<10?'0'+i:i;domSeconds += '<li><span>' + i + '</span></li>';}
            $('#d-seconds').html(emptyStr + domSeconds + emptyStr);
        },
        bissextile:function(year,month){
            var day;
            if (month == 1 || month == 3 || month == 5 || month == 7 || month == 8 || month == 10 || month == 12) {
                day = 31
            } else if (month == 4 || month == 6 || month == 11 || month == 9) {
                day = 30
            } else if (month == 2) {
				if (year % 4 == 0 && (year % 100 != 0 || year % 400 == 0)) { //闰年
					day = 29
				} else {
					day = 28
				}

			}
			return day;
        },
        slide:function(el){
            //滑动
            var T,mT,isPress = false;
            $(doc).on(tstart,'#date-wrapper ol', function(e){
                var e = e.originalEvent;
                e.stopPropagation();
                addEventListener();
                T = e.pageY || e.touches[0].pageY;
                if(!isTouch){isPress = true;}
            })
            $(doc).on(tmove,'#date-wrapper ol', function(e){
                var e = e.originalEvent,that = $(this);
                e.stopPropagation();
                addEventListener();
                if(!isTouch && !isPress){return false};
                mT = e.pageY || e.touches[0].pageY;
                that.css('top', that.position().top + (mT - T) + 'px');
                T = mT;
                if (that.position().top > 0) that.css('top', '0');
                if (that.position().top < -(that.height() - (3*resH))) that.css('top', '-' + (that.height() - (3*resH)) + 'px');
            })
            $(doc).on(tend,'#date-wrapper ol', function(e){
                var e = e.originalEvent,that = $(this);
                e.stopPropagation();
                addEventListener();
                isPress = false;
                dragEnd(that);
            })
            $(doc).on(tcancel,'#date-wrapper ol', function(e){
                var e = e.originalEvent,that = $(this);
                e.stopPropagation();
                addEventListener();
                isPress = false;
				// 解决一个pc端莫名触发问题
				if(!isTouch && + new Date() > time + 600){
					dragEnd(that);
				}
            })
            function dragEnd(that){
                //滚动调整
                var t = that.position().top;
                that.css('top',Math.round(t/resH)*resH+'px');
                //定位active
                t = Math.round(Math.abs($(that).position().top));
                var li = that.children('li').get(t/resH+1);
                $(li).addClass('active').siblings().removeClass('active');
                //修正日期
                var id = that.attr('id');
                if(id == 'd-month' || id == 'd-year'){
					var elDay = $('#d-day');
                    if(elDay.length == 0){return false;}
                    var end = createDate.bissextile($('#d-year .active').text(),$('#d-month .active').text());
                    if(end != (elDay.children().length-2)){
                        var active = elDay.children('.active').text();
						
                        active > end && (active = end);
                        createDate.d(end,active);
                        if(Math.abs(elDay.position().top) > elDay.height()-3*resH)elDay.css('top','-'+(elDay.height()-3*resH)+'px');
                    }
                }
            }
        },
        show:function(isShow){
            var domMain = $('#date-wrapper'),
                domMask = $('#d-mask');
            if (isShow) {
                domMain.show();
                domMask.show();
				time = + new Date();
                body.css('overflow','hidden');
            } else {
                domMain.hide();
                domMask.hide();
                body.css('overflow','auto');
            }
        },
        resetActive:function(){
             var d = new Date();
            if(opt.limitTime == 'tomorrow'){
                d.setDate(d.getDate()+1);
            }
			$('#date-wrapper ol').each(function() {
                var e = $(this),
                eId = e.attr('id');
                e.children('li').each(function() {
                    var li = $(this),liText = Number(li.text() == ''? 'false':li.text());
                    if (eId == 'd-year' && liText === d.getFullYear()) {
                        li.addClass('active').siblings().removeClass('active');
                        return false;
                    } else if (eId == 'd-month' && liText === (d.getMonth() + 1)) {
                        li.addClass('active').siblings().removeClass('active');
                        return false;
                    } else if (eId == 'd-day' && liText === d.getDate()) {
                        li.addClass('active').siblings().removeClass('active');
                        return false;
                    } else if (eId == 'd-hours' && liText === d.getHours()) {
                        li.addClass('active').siblings().removeClass('active');
                        return false;
                    } else if (eId == 'd-minutes' && liText === d.getMinutes()) {
                        li.addClass('active').siblings().removeClass('active');
                        return false;
                    } else if (eId == 'd-seconds' && liText === d.getSeconds()) {
                        li.addClass('active').siblings().removeClass('active');
                        return false;
                    }
                })
            })
        },
        toNow:function(refresh){
            if (!refresh) {
                $('#date-wrapper ol').each(function(){
                    var that = $(this);
                    var liTop = -(that.children('.active').position().top -resH);
                    that.animate({
                        top: liTop
                    },
                    600);
                })
            } else {
                $('#date-wrapper ol').each(function() {
                    $(this).animate({
                        top: 0
                    },
                    0);
                })
            }
        },
        clear:function(){
            createDate.toNow(true);
            createDate.show(false);
        }
    }
	createDate.m();
	createDate.d();
	createDate.hm();
	createDate.s();
    createDate.slide();
	
    var opt,
        userOption,
		el = $('#date-wrapper'),
		elTit = $('#d-tit'),
		elBg = $('#d-bg'),
		prevY = '';
		
    function DateTool(obj){
        var that = $(obj);
        that.bind('click',function() {
			if(that.get(0).tagName == 'INPUT'){that.blur();}
			userOption = that.data('options');
			if(typeof(userOption) == 'string'){userOption = JSON.parse(userOption.replace(/'/g,'"'));}
            if (!el.is(':visible')) {
				opt = null;
				opt = $.extend({},opts,userOption || {});
				var y = '' + opt.beginYear + opt.endYear;
				if(prevY != y){
					createDate.y(opt.beginYear,opt.endYear);
					prevY = y;
				}
				if(dateFormat[0].indexOf(opt.type) != -1){//年月日 时分秒
					elTit.children().show();
					elBg.children().show();
					el.attr('class','');
				}else if(dateFormat[1].indexOf(opt.type) != -1){//年月日 时分
					elTit.children().show().end().children(':gt(4)').hide();
					elBg.children().show().end().children(':gt(4)').hide();
					el.attr('class','five');
				}else if(dateFormat[2].indexOf(opt.type) != -1){//年月日
					elTit.children().show().end().children(':gt(2)').hide();
					elBg.children().show().end().children(':gt(2)').hide();
					el.attr('class','three');
				}else if(dateFormat[3].indexOf(opt.type) != -1){//年月
					elTit.children().show().end().children(':gt(1)').hide();
					elBg.children().show().end().children(':gt(1)').hide();
					el.attr('class','two');
				}
                createDate.resetActive();
                createDate.show(true);
                createDate.toNow(false);
                $('#d-confirm').attr('d-id', obj);
            }
        });
    }
    $.date = function(obj){
		DateTool(obj);
	}
    //取消
    $('#d-cancel,#d-mask').bind('click',function(){
        createDate.clear();
    })
    //确定
    $('#d-confirm').bind('click',function(){
        var y = $('#d-year .active').text(),
			m = $('#d-month .active').text(),
			d = $('#d-day .active').text(),
			h = $('#d-hours .active').text(),
			min = $('#d-minutes .active').text(),
			s = $('#d-seconds .active').text(),
			str,
			that = $($(this).attr('d-id')),
            index = dateFormat[0].indexOf(opt.type),
            index1 = dateFormat[1].indexOf(opt.type),
            index2 = dateFormat[2].indexOf(opt.type),
            index3 = dateFormat[3].indexOf(opt.type);
			
        if( index != -1){//年月日 时分秒
            switch(index){
				case 0:
				  str = y+'-'+m+'-'+d+' '+h+':'+min+':'+s;
				  break;
				case 1:
				  str = y.substring(2)+'-'+m+'-'+d+' '+h+':'+min+':'+s;
				  break;
				case 2:
				  str = y+'/'+m+'/'+d+' '+h+':'+min+':'+s;
				  break;
				case 3:
				  str = y.substring(2)+'/'+m+'/'+d+' '+h+':'+min+':'+s;
				  break;
			}  
        }else if(index1 != -1){//年月日 时分
            switch(index1){
				case 0:
				  str = y+'-'+m+'-'+d+' '+h+':'+min;
				  break;
				case 1:
				  str = y.substring(2)+'-'+m+'-'+d+' '+h+':'+min;
				  break;
				case 2:
				  str = y+'/'+m+'/'+d+' '+h+':'+min;
				  break;
				case 3:
				  str = y.substring(2)+'/'+m+'/'+d+' '+h+':'+min;
				  break;
			}  
        }else if(index2 != -1){//年月日
            switch(index2){
				case 0:
				  str = y+'-'+m+'-'+d;
				  break;
				case 1:
				  str = y.substring(2)+'-'+m+'-'+d;
				  break;
				case 2:
				  str = y+'/'+m+'/'+d;
				  break;
				case 3:
				  str = y.substring(2)+'/'+m+'/'+d;
				  break;
			}  
        }else if(index3 != -1){//年月
            switch(index3){
				case 0:
				  str = y+'-'+m;
				  break;
				case 1:
				  str = y.substring(2)+'-'+m;
				  break;
				case 2:
				  str = y+'/'+m;
				  break;
				case 3:
				  str = y.substring(2)+'/'+m;
				  break;
			}  
        }
        if(opt.limitTime == 'today'){
            var d = new Date(),
				error = !isEnglish ? '不能选择过去的时间':'You can\'t choose the past time';
            //当前日期
            var day = String(d.getFullYear())+'-'+String(d.getMonth() + 1)+'-'+String(d.getDate());
            var d1 = new Date(str.replace(/\-/g, "\/")); 
            var d2 = new Date(day.replace(/\-/g, "\/"));
            if(d1 < d2){
                alert(error);
                return false;
            }  
        }else if(opt.limitTime == 'tomorrow'){
            var d = new Date(),
				error = !isEnglish ? '时间最少选择明天':'Choose tomorrow at least';
            //当前日期+1
            var day = String(d.getFullYear())+'-'+String(d.getMonth() + 1)+'-'+String(d.getDate()+1);
            var d1 = new Date(str.replace(/\-/g, "\/")); 
            var d2 = new Date(day.replace(/\-/g, "\/"));
            if(d1 < d2){
                alert(error);
                return false;
            }  
        }
        //赋值
        if(that.get(0).tagName == 'INPUT'){
            that.val(str);
        }else{
            that.text(str);
        }

        createDate.show(false);
        createDate.toNow(true);
    })
}));

function addEventListener(){
   document.addEventListener('touchmove', function (event) {
       event.preventDefault();
	}, {
	    passive: false
	});
}

html的代码:

<!DOCTYPE html>
<html lang="zh-cn">
<head>
	<meta charset="UTF-8">
	<meta name="viewport" content="width=device-width, initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0, user-scalable=no">
	<title>date demo</title>
	<style type="text/css">
		strong{
			font-size: 15px;
		}
		pre{
			padding: 16px 0;
			line-height: 1.45;
			background-color: #f6f8fa;
			border-radius: 3px;
		}
	</style>
</head>
<body>
	<pre>
	<strong>jquery-date.js</strong>

	 <b>配置:</b>
	 //不填则使用默认配置
	 data-options="{'type':'YYYY-MM-DD hh:mm:ss','beginYear':2010,'endYear':2088}"

	 <b>调用方式:</b>
	 $.date('#date');

	 <b>参数说明:</b>
	 type--支持的格式
	//年月日 时分秒
	['YYYY-MM-DD hh:mm:ss','YY-MM-DD hh:mm:ss','YYYY/MM/DD hh:mm:ss','YY/MM/DD hh:mm:ss']
	//年月日 时分
	['YYYY-MM-DD hh:mm','YY-MM-DD hh:mm','YYYY/MM/DD hh:mm','YY/MM/DD hh:mm']
	//年月日
	['YYYY-MM-DD','YY-MM-DD','YYYY/MM/DD','YY/MM/DD']
	//年月
	['YYYY-MM','YY-MM','YYYY/MM','YY/MM']

	beginYear -- 开始年份

	endYear -- 结束年份,可不填,默认不会小于当前

	limitTime--可选 today:今天之前的日期不可选 tomorrow:明天之前的不可选
	</pre>
	<h3>演示</h3>
	<hr>
	年月
	<br>
	<input type="text" id="date" data-options="{'type':'YYYY-MM','beginYear':2010,'endYear':2088}" style="width:166px;height:19px;">
	<hr>
	年月日
	<br>
	<input type="text" id="date2" data-options="{'type':'YYYY-MM-DD','beginYear':2010,'endYear':2088}" style="width:166px;height:19px;">
	<hr>
	年月日 时分
	<br>
	<input type="text" id="date3" data-options="{'type':'YYYY-MM-DD hh:mm','beginYear':2010,'endYear':2088}" style="width:166px;height:19px;">
	<hr>
	年月日 时分秒
	<br>
	<button type="text" id="date4" data-options="{'type':'YYYY-MM-DD hh:mm:ss','beginYear':2010,'endYear':2088}" style="width:170px;height:25px;vertical-align: middle;text-align: left;"></button>
	<hr>
	时间限制
	<br>
	<input type="text" id="date5" data-options="{'type':'YYYY-MM-DD','beginYear':2010,'endYear':2088,'limitTime':'today'}" style="width:166px;height:19px;">
	<br>
	<br>
	<br>
	<script src="jquery/jquery1.8.3.min.js"></script>
	<script src="jquery.date.js"></script>
	<script>
		$.date('#date');
		$.date('#date2');
		$.date('#date3');
		$.date('#date4');
		$.date('#date5');
	</script>
</body>
</html>

 

1.在chrome或者高版本的安卓手机上e.preventDefault就没有效果。会报Unable to preventDefault inside passive event listener due to target being treated as passive.错误。

解决办法:在jquery.date.js加一个函数(addEventListener),由函数代替event.preventDefault()就可以了:

function addEventListener(){
   document.addEventListener('touchmove', function (event) {
       event.preventDefault();
    }, {
        passive: false
    });
}   

2.报错信息:Ignored attempt to cancel a touchmove event with cancelable=false, for example because scrolling is in progress and cannot be interrupted.怎么解决.

这是忽略尝试取消具有cancelable = false的touchmove事件,例如因为滚动正在进行且无法中断,解决办法:

在CSS中加上touch-action: none;就可以了

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值