1. 程式人生 > >行程日曆元件:選擇開始和結束日期+滑動選擇時間

行程日曆元件:選擇開始和結束日期+滑動選擇時間

前一篇文章剛給大家分享了滑動元件(http://blog.csdn.net/sq_zhuyi/article/details/79103683),本篇文章就正好利用到這個滑動元件,在日曆控制元件中實現選擇時間的模組。同樣,為了便於入題,我們先看效果圖:


這是一個在租車專案中選擇取車時間和還車時間的日曆,其實同樣的場景被用於很多旅遊專案,用來選擇出發、返程時間。

上程式碼,CSS模組:

.acal {
    position: absolute;
    left: 0;
    right: 0;
    top: 44px;
    z-index: 100;
}

.acal .head {
    position: fixed;
    left: 0;
    right: 0;
    top: 44px;
    z-index: 12;
    height: 44px;
    padding: 0 25px;
    border-top: 1px solid #ddd;
    border-bottom: 1px solid #ddd;
    background-color: #fff;
    text-align: center;
}
.acal .head .dt {
    line-height: 44px;
    font-size: 18px;
}
.acal .head .day {
    width: 3.5em;
    line-height: 26px;
    border: 1px solid #f00;
    border-radius: 8px;
    margin-top: 8px;
}

.acal .week {
    position: fixed;
    left: 0;
    right: 0;
    top: 88px;
    z-index: 11;
    line-height: 32px;
    text-align: center;
    background-color: #fff;
    border-bottom: 1px solid #eee;
    box-shadow: 0 2px 20px rgba(0,0,0,0.2);
}
.acal .week>i {
    width: 14.28%;
}

.acal .calbody {
    padding: 80px 0 200px 0;
    background-color: #f9f9f9;
}
.acal .month {
    position: relative;
}
.acal .month>h2 {
    text-align: center;
    line-height: 295px;
    font-size: 80px;
    color: #dedede;
    font-weight: normal;
}
.acal .month .days {
    position: absolute;
    left: 0;
    right: 0;
    top: 0;
    bottom: 0;
}
.acal .month .days>i {
    float: left;
    width: 59px;
    height: 39px;
    margin: 10px 0;
    text-align: center;
    font-size: 20px;
    position: relative;
}
.acal .month .days em {
    width: 39px;
    line-height: 39px;
    border-radius: 50%;
    position: absolute;
    left: 10px;
    top: 0;
    z-index: 2;
}
.acal .month .days>i.disabled {
    color: #999;
}
.acal .month .days>i.hover {
    color: #fff;
}
.acal .month .days>i.hover>em {
    background-color: #f00;
}
.acal .month .days>i.hover::before {
    content: "";
    position: absolute;
    top: 0;
    bottom: 0;
    z-index: 1;
    background-color: #FFD2CF;
}
.acal .month .days>i.start::before {
    left: 30px;
    right: 0;
}
.acal .month .days>i.end::before {
    left: 0;
    right: 30px;
}
.acal .month .days>i.active {
    background-color: #FFD2CF;
}

.acal .time {
    position: fixed;
    left: 0;
    right: 0;
    bottom: 60px;
    z-index: 10;
    border-top: 1px solid #eee;
    background-color: #fff;
    box-shadow: 0 -2px 20px rgba(0,0,0,0.2);
}
.acal .time .tit {
    float: left;
    font-size: 16px;
    width: 100px;
    text-indent: 14px;
    line-height: 56px;
}
.acal .time .slide {
    float: left;
    width: 300px;
    height: 2px;
    margin-top: 26px;
    background-color: #ddd;
}
.acal .time .value {
    float: left;
    height: 2px;
    background-color: #f00;
    position: relative;
}
.acal .time .value>em {
    position: absolute;
    right: -30px;
    top: -10px;
    line-height: 22px;
    padding: 0 6px;
    border: 1px solid #f00;
    background-color: #fff;
    border-radius: 20px;
}

日期模組:

/**
 * 日曆
 * @param {object} options 
 * @param {number} options.minday 最少提前幾天預定
 * @param {number} options.months 顯示幾個月
 * @param {date} options.start 預設開始時間
 * @param {date} options.end 預設結束時間
 * @param {function} options.callback 選擇時間後的回撥函式
 */
function Calendar(options) {
    this.options = options;
    this.options.daysel = '.acal .days>i';

    this.init();
}

Calendar.prototype.init = function () {
    var ins = this;
    if($('.acal').length==0){
        ins._createDOM();
        ins._bindEvent();
    }
    // 初始化日期-
    var start = ins.options.start;
    var m1 = $('.acal [data-m="{0}-{1}"]'.format(start.getFullYear(), start.getMonth()));
    var d1 = m1.next().find('[data-d="{0}"]'.format(start.getDate()));
    d1.trigger('click');
    
    var end = ins.options.end;
    var m2 = $('.acal [data-m="{0}-{1}"]'.format(end.getFullYear(), end.getMonth()));
    var d2 = m2.next().find('[data-d="{0}"]'.format(end.getDate()));
    d2.trigger('click');


    // 初始化時間-
    var arr = $('.acal .time em');
    var t1 = start.date(5).split(' ')[1];
    arr.eq(0).html(t1).parent().data('value', t1);
    var t2 = end.date(5).split(' ')[1];
    arr.eq(1).html(t1).parent().data('value', t2);

    var tt = [];
    for (var i = 0; i < 24; i++) {
        tt.push(i + ':00');
        tt.push(i + ':30');
    }
    new Slider({
        bar: $('.acal .slide').eq(0),
        btn: $('.acal .slide em').eq(0),
        data: tt,
        width: 300,
        callback: ins.setValue.bind(ins)
    }).init();
    new Slider({
        bar: $('.acal .slide').eq(1),
        btn: $('.acal .slide em').eq(1),
        data: tt,
        width: 300,
        callback: ins.setValue.bind(ins)
    }).init();
    
    ins.setValue();
};
Calendar.prototype.hide = function () {
    $('.acal').css('display', 'none');
}
Calendar.prototype.show = function () {
    $('.acal').css('display', 'block');
}

Calendar.prototype._bindEvent = function () {
    var ins = this;
    var options = this.options;
    $(options.daysel).on('click', function () {
        var $t = $(this);
        if ($t.hasClass('disabled')) return;

        var len = $(options.daysel + '.hover').length;
        $t.addClass('hover');
        if (len == 1) {
            ins._resetDate();
        } else if (len == 2) {
            $(options.daysel).removeClass('hover active start end');
            $t.addClass('hover');
        }
    });
    $('.acal .btn-red').on('click', function(){
        ins.hide();
        if(ins.options.callback){
            ins.options.callback(options.start, options.end);
        }
    });
}

Calendar.prototype._createDOM = function () {
    var ss = '<div class="acal" style="display:none;">' +
        '<div class="head"><i class="left dt"></i><i class="day"></i><i class="right dt"></i></div>' +
        '<div class="week"><i>日</i><i>一</i><i>二</i><i>三</i><i>四</i><i>五</i><i>六</i></div>' +
        '<div class="calbody"></div>' +
        // time start
        '<div class="time">' +
        '<div class="row clearfix">' +
        '<i class="tit">取車時間</i>' +
        '<div class="slide"><div class="value" data-value="10:00"><em>10:00</em></div></div>' +
        '</div>' +
        '<div class="row clearfix">' +
        '<i class="tit">還車時間</i>' +
        '<div class="slide"><div class="value" data-value="10:00"><em>10:00</em></div></div>' +
        '</div>' +
        '</div>' +
        // time end
        '<div class="footbar"><a class="btn-red">確認</a></div>' +
        '</div>';
    $('body').append(ss);
    this._createMonth();
}

Calendar.prototype._createMonth = function () {
    var options = this.options;
    var s0 = '<div class="month"><h2 data-m="{2}-{3}">{0}月</h2><div class="days">{1}</div></div>';
    var s1 = '<i data-d="{0}"><em>{0}</em></i>';
    var s2 = '<i class="disabled"><em>{0}</em></i>';
    var ss = '';
    var now = new Date();
    var arr = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31];
    for (var i = 0; i < options.months; i++) {
        var dt = new Date(now.getFullYear(), now.getMonth() + i, 1);
        let max = arr[dt.getMonth()];
        if (dt.getFullYear() % 4 == 0 && dt.getMonth() == 1) max += 1;
        var s = '',
            d0 = 0;
        // 從正確的周N開始-
        while (d0 < dt.getDay()) {
            s += s2.format('');
            d0++;
        }
        for (var d = 1; d <= max; d++) {
            var disabled = (i == 0) && (d < now.getDate() + options.minday);
            s += (disabled ? s2 : s1).format(d);
        }
        // 不足一個月補全-
        var d1 = 7 - (d0 + max) % 7;
        while (d1 > 0) {
            s += s2.format('');
            d1--;
        }
        ss += s0.format(dt.getMonth() + 1, s, dt.getFullYear(), dt.getMonth());
    }
    $('.calbody').html(ss);
}

Calendar.prototype._resetDate = function () {
    var arr = $(this.options.daysel + '.hover');
    var d1 = arr.eq(0).addClass('start');
    var d2 = arr.eq(1).addClass('end');

    var next = d1.next();
    while (!next.hasClass('end')) {
        next.addClass('active');
        next = next.next();
        if (next.length == 0) {
            next = d1.parent().parent().next().find('.days>i').eq(0);
        }
    }
    this.setValue();
}
// 將最終的日期set到頭部-
Calendar.prototype.setValue = function(){
    var options = this.options;
    var d1 = $(options.daysel + '.start');
    var d2 = $(options.daysel + '.end');

    var arr = $('.acal .time em');
    var t1 = arr.eq(0).html() || '10:00';
    var t2 = arr.eq(1).html() || '10:00';

    function getDT(d, t){
        var ym = d.parent().prev().data('m').split('-');
        var s = '{0}-{1}-{2} {3}'.format(ym[0], ym[1]-0+1, d.data('d'), t);
        return s.date(1);
    }
    options.start = getDT(d1, t1);
    options.end = getDT(d2, t2);

    $('.acal .head .dt').eq(0).html(options.start.date(4).replace('-','月').replace(' ','日 '));
    $('.acal .head .dt').eq(1).html(options.end.date(4).replace('-','月').replace(' ','日 '));
    
    $('.acal .head .day').html(av.days(options.start, options.end)+'天');
};

時間模組:
/**
 * 滑動模組
 * @param {object} options 
 * @param {jquery} options.bar 進度條
 * @param {jquery} options.btn 按鈕
 * @param {Array} options.data 進度條上的資料
 * @param {number} options.width 進度條寬度(可選)
 * @param {function} options.callback 選擇後的回撥
 */
function Slider(options) {
    this.options = options;
    this.init();
}

Slider.prototype.init = function () {
    var ins = this;
    if (ins.options.steps) {
        return; // 只init一次-
    }
    // 將整個bar分隔成N個寬度-
    var steps = [];
    var ww = ins.options.width || ins.options.bar[0].offsetWidth;
    var w = (ww - 20) / (ins.options.data.length - 1);
    $.each(ins.options.data, function (i, v) {
        steps[i] = w * i;
    });
    ins.options.steps = steps;

    var $v = ins.options.btn.parent();
    var val = $v.data('value');
    if (!val) {
        val = ins.options.data[0];
    }
    ins.setValue(val);
    $.each(ins.options.data, function (i, v) {
        if (val == v) {
            $v.width(ins.options.steps[i]);
        }
    });

    // 繫結btn事件-
    ins.bindEvent();
};
Slider.prototype.setValue = function (value) {
    this.options.btn.html(value).parent().data('value', value);
};
Slider.prototype.bindEvent = function () {
    var ins = this;
    var $b = ins.options.btn;
    var $v = $b.parent();
    var x0 = 0, // 滑鼠按下位置-
        x1 = 0, // 滑鼠移動過程的位置-
        w0 = 0; // 滑動前的value大小-

    $b.on('mousedown touchstart', function (event) {
        x0 = event.clientX || event.touches[0].clientX;
        w0 = $v.width();
        w2 = ins.options.width || ins.options.bar[0].offsetWidth;
    }).on('mousemove touchmove', function (event) {
        if (x0 == 0) return;
        x1 = event.clientX || event.touches[0].clientX;
        var w1 = w0 + x1 - x0;
        if (w1 > w2) return;
        $v.width(w1);
        var val = getNewValue(w1);
        if (val != $v.data('value')) {
            ins.setValue(val);
        }
    }).on('mouseup touchend', function (event) {
        x0 = x1 = 0;
        if(ins.options.callback){
            ins.options.callback();
        }
    });

    // 根據當前value寬度獲取對應的data-
    function getNewValue(w) {
        var max = 0;
        $.each(ins.options.steps, function (i, v) {
            if (w > v) max = i;
        });
        return ins.options.data[max];
    }
};

大家已經發現,該日曆元件主要用於移動端專案,但JavaScript程式碼其實不區分客戶端的,稍微修改CSS程式碼,一樣用於PC端裝置。

作者:朱會震

相關推薦

行程日曆元件選擇開始結束日期+滑動選擇時間

前一篇文章剛給大家分享了滑動元件(http://blog.csdn.net/sq_zhuyi/article/details/79103683),本篇文章就正好利用到這個滑動元件,在日曆控制元件中實現選擇時間的模組。同樣,為了便於入題,我們先看效果圖:這是一個在租車專案中選擇

vue移動端日曆元件 mintUi dateTime picker 設定開始結束日期

=====================================追加提示2018.9.17=============================== 繼續填坑  如果你想修改  這個元件的 取消和確定按鈕   則需要像下面的startDate

java 使用Calendar類計算每月有多少自然周,並輸出每週的開始結束日期

思路:首先是獲取該月的實際天數,然後從1號遍歷直至該月最後一天,利用Calendar類找出該日是一週中的第幾天, (1)若該日是週日,則視為一週結束,並用該日期減去6找到該周的開始日期,若相減結果小於等於1,則說明該周起始日期應該是本月1號。 (1)若該日不是週日,且

EasyUI日曆元件datebox開始時間結束日期在一月範圍內選取

$("#datebox1").datebox('calendar').calendar({ validator:function(beginDate){ var date = new Date();//今天 var

EasyUI 日曆控制元件之--限制日曆開始結束時間

首先引入EasyUI所需資源 <link rel="stylesheet" type="text/css" href="../../themes/default/easyui.css"> <link rel="stylesheet" type="text/css" hr

dtIntersectSegmentPoly2D 2D上的線段與多邊形相交計算 產生結果是否相交,線段跨越的開始結束百分比,相交的邊

align lin wid con ont html jpg erp const dtIntersectSegmentPoly2D(startPos, endPos, verts, nv, tmin, tmax, segMin, segMax): http://g

從下拉框中選擇年份該年的週數,計算出該周的開始日期結束日期

 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">   <h

java 日曆工具類(計算周的開始日期結束日期,以及包好的日期

package com.zxy.product.training.web.util; import java.text.ParseException; import java.text.SimpleDateFormat; import java.util.ArrayList

多個倒計時切換 開始結束

move 顯示 ont tin call () doc loop script /* * @Author: Mark * @Date: 2015-08-06 13:54:01 * @Last Modified by: Mark * @Last Modified

C# GetValueList 獲得字符串中開始結束字符串中間得值列表

mat 字符串 開始 true private ref uri cnblogs 字符 /// <summary> /// 獲得字符串中開始和結束字符串中間得值列表 /// </summary>

獲得字符串中開始結束字符串中間得值

new single returns div 字符串 name ram rim color 1 /// <summary> 2 /// 獲得字符串中開始和結束字符串中間得值 3 /// </summary>

end是觸發器開始結束的標記,

date 安全 之間 添加 安全性 有意義 mysql語句 tro .com 什麽是MYSQL觸發器,我們先了解一下觸發的意思。觸發的字面意思是指因觸動而激發起某種反應。 MYSQL必知必會中對觸發器的解釋是:MySQL響應以下任意語句而自動執行的一條MySQL語句(或位於

C# 發送http方法,利用鍵值對 KeyValuePair,發送分頁命令,日歷的開始結束時間命令(POST)

!= 方法 call value face all 發送 keyvalue analysis 一個HTTP的類裏面: public static string HttpClientPost(string url, string taskIdx, string

特效序列幀動畫,可指定開始結束

 直接貼程式碼: Shader "James/FX/MeshFrame" { Properties { [Enum(Add, 1, Blend, 10)] _DstBlend ("Blend Mode", Float) = 1 _Ma

c#獲取當前時間的本週、本月、本季、本年的開始結束時間

using System; public enum DataTimeType { Week, Month, Season, Year } public class DataTimeManager { /// <summary> ///

IPV 6 / IPV 4大小比較,判斷IPV6/IPV4範圍的開始結束

IP 比較大小的目的是為了確認IP 範圍的正確性,前提是必須是同一網段的 原理:舉個IPV 4 的例子: 127.0.0.1 和 128.0.0.2 是不同的兩個網段,不同網段下邊的IP是無法對比大小的,因為互不通訊,互不影響。 只有在同一個網段的兩個 IP 才能比較大小,

c# 用正則表示式獲取開始結束字串中間的值

/// <summary> /// 獲得字串中開始和結束字串中間得值 /// </summary> /// <param name="str">字串</param> /// <param name="s">開始</param>

obtain start and end timestamp of last week, with set of hour/minute/second 獲取上週開始結束時間戳,可以設定時分秒

var now=new Date()var nowDayOfWeek = now.getDay(); //今天本週的第幾天var nowDay = now.getDate(); //當前日var nowMonth = now.getMonth(); //當前月var nowYear = now.getFull

TCP協議詳解之TCP Flag標誌位來判斷TCP會話的開始結束

首先回顧一下TCP標誌位的具體含義。 TCP Flag標誌位(控制位) 一個TCP包的詳細內容: TCP FLAG 標記佔1.5個byte,12bit(4bit+8bit,前半個byte與Header Length公用)。 12bit中前三個bit是保留,預設為全0

獲取本週、上週、本月、上月 的開始日期結束日期

方法返回的是一個物件:  {startDate: 年-月-日,  endDate: 年-月-日}使用方法: 獲取上月 :getAppointedDate(2, 1)        獲取上週 getAppointedDate(1,