IT博客汇
  • 首页
  • 精华
  • 技术
  • 设计
  • 资讯
  • 扯淡
  • 权利声明
  • 登录 注册

    通过DateQuery完善倒计时、日历所需的常用功能

    李惟发表于 2014-11-11 08:47:40
    love 0

    DateQuery是本人些的一个时间操作类,类库的文档可在此查看:

    一行JS搞定时间增删改、倒计时,来自类库:lv-js

    http://levi.yii.so/archives/3690

    这个类库本身是作为方便操作时间的对象,不过发布后看来,不少朋友对“倒计时”这个功能很感兴趣,所以这里我就围绕这个来说说这个类库的特性,在篇尾还会顺带提一提,新增加的walk方法,对于需要做日历、时间提醒等插件的朋友,很有帮助哟~

    倒计时

    最简单的一个倒计时,核心代码:

    setInterval(function() {
        lv.date().set('2015-11-12 11:00:20', true).get('g', true);
    }, 100);

    上面代码的意思是设置一个截止时间为:2015-11-12 11:00:20 的DateQuery对象,每100秒取一次时间差。当然如果将上面代码如下优化,可能会更好哦:

    // 先申明一个DateQuery对象
    var date = lv.date().set('2015-11-12 11:00:20', true);
    
    // 每100毫秒获取一次时间差
    setInterval(function() {
        date.set().get('g', true);    // 注意这里的set哦,他会自动更新当前时间
    }, 100);

    具体方法请参考文档:http://levi.yii.so/archives/3690

    提供一个在线演示:

    后来一朋友提出这么一个需求:

    • 希望能够防止用户修改本地时间
    • 从服务器获取时间,而非本地

    于是当时给出了这么一个“理想”状态的代码:

    // 初始时间是服务端给的哦,set的时间可以是固定值
    var date = lv.date('2014-10-27 18:00:00').set('2014-11-27 18:00:00', true);
    
    // 每100毫秒递增时间
    setInterval(function() {
        date.add(100).get('g', true);
    }, 100);

    当然这仅仅是“理想”状态,实际使用过程中会有“延迟”,为什么会出现“延迟”。这里说下并非类库本身的BUG,而是在于这段代码设计的不太合理,并没有考虑setInterval的“延迟”时间,做个测试如下:

    // 还是刚才那段代码
    var date = lv.date('2014-10-27 18:00:00').set('2014-11-27 18:00:00', true);
    
    // 设置两个时间点
    var test = lv.date(), test_aft;
    
    // 每100毫秒递增时间
    setInterval(function() {
        date.add(67).get('g', true);
    
        // 将执行后的时间和执行前进行比较后
        test_aft = lv.date();
        console.log(test.diff(null, test_aft) - 67);
    
        test.set(test_aft);    // 更新时间
    }, 67);

    以上代码拷贝放入chrome调试器中查看,你会发现没次setInterval回调都会延迟0-2毫秒的时间,累计后则会有较明显的“时间计算错误”

    题外话:diff这个方法设计之初也单纯只是作为对比,设计出来后发现这个方法,还可以作为代码调试用途,例如:帮你统计代码执行时间、程序的效率等问题

    很显然这样就不符合实际需求了,那如何做到“避免用户篡改时间”?这里我提供两个方法:

    定时效验:

    // 还是刚才那段代码
    var date = lv.date('2014-10-27 18:00:00').set('2014-11-27 18:00:00', true),
        time = lv.date();
    
    // 每100毫秒递增时间
    setInterval(function() {
        // 每隔3分钟,向服务器发起请求进行效验
        if (lv.date().diff(null, timg) > 18000) {
            // 这里的Ajax方法省略,大家可以通过jquery或其他方法实现
            httpAjax('url', function(serverTime) {
                date.set(serverTime); // 从服务器上获取效验后的时间
                time.set(); // 别忘记了同时更新本地时间
            });
        }
    
        date.add(100).get('g', true);
    }, 100);

    当然这个方法非常占用资源,不建议这么实现

    结果效验

    这个方法只效验结果,不效验过程,最终向服务器只提交一次请求来判断是否正常。使用的是“本地时间”,而非“服务器时间”,代码如下:

    // 先申明一个DateQuery对象
    var date = lv.date().set('2015-11-12 11:00:20', true), val;
    
    // 每100毫秒获取一次时间差
    setInterval(function() {
        val = date.set().get('g', true);
        if (!val[0]) {
            // 这里的Ajax方法省略,大家可以通过jquery或其他方法实现
            httpAjax('url', function(status) {
                !status && alert('您本地时间设置不正确');
            });
        }
    }, 100);

    以上就是我提供的“倒计时防作弊”的方法,如果你有更好的解决方案,可以留言告诉我哦。

    3行一个日历

    出了倒计时之外,使用这个类库,还能极大的方便设计日历,核心代码如下:

    lv.date().walk('m', 'd', function() {
        console.log(this.get('Y-m-d 星期:') + ['日', '一', '二', '三', '四', '五', '六'][this.get('w')]);
    });

    通过上面的方法,会将当前月份,以天为间隔单位,通过闭包的方式循环输出lv.date对象(剩下的,只需在闭包中通过get方法,输出指定时间格式)。

    当然你也可以一次性输出2个月的时间、3个月的时间、一周的时间,这个随意,具体请查看文档:http://levi.yii.so/archives/3690

    下面是我自己做的一个简单的日历,借用了jquery作为Dom操作:

    您可能也喜欢:

    初识 jQuery Deferred

    一句话删除目录下所有文件

    开发者:为自己的App制作一个专属网页吧

    WEB前端底层知识--浏览器是如何工作的

    使用CloudFlare提升网站的访问体验和安全性
    无觅


沪ICP备19023445号-2号
友情链接