JQuery日期选择插件

#   JQuery日期选择插件



----index.html----------------------------------------------------------------------------
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta http-equiv='Content-Type' content='text/html; charset=utf-8'>
<meta http-equiv="x-ua-compatible" content="IE=edge, chrome=1">
<meta http-equiv="X-UA-Compatible" content="IE=9; IE=8;">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>jQuery事件日历插件Calendar</title>
<link rel="stylesheet" href="calendar.css">
<style type="text/css">
html {
	font: 500 14px 'roboto';
	color: #333;
	background-color: #fafafa;
}
a {
	text-decoration: none;
}
ul, ol, li {
	list-style: none;
	padding: 0;
	margin: 0;
}
#demo {
	width: 300px;
	margin: 150px auto;
}
p {
	margin: 0;
}
#dt {
	margin: 30px auto;
	height: 28px;
	width: 200px;
	padding: 0 6px;
	border: 1px solid #ccc;
	outline: none;
}
</style>
</head>
<body>
<div id="demo">

  <input type="text" id="dt" placeholder="trigger calendar">
  <div id="dd"></div>
</div>
<script src="js/jquery.js"></script> 
<script src="js/calendar.js"></script> 
<script>


    $('#dd').calendar({
        trigger: '#dt',
        zIndex: 999,
		format: 'yyyy-mm-dd',
        onSelected: function (view, date, data) {
            console.log('event: onSelected')
        },
        onClose: function (view, date, data) {
            console.log('event: onClose')
            console.log('view:' + view)
            console.log('date:' + date)
            console.log('data:' + (data || 'None'));
        }
    });
</script>


</body>
</html>
---calendar.css---------------------------------------------------------------------
.calendar {
    width: 280px;
    height: 330px;
}
.calendar-modal {
    display: none;
    position: absolute;
    background: #fdfdfd;
    border: 1px solid #e8e8e8;
    box-shadow: 1px 2px 3px #ddd
}
.calendar-inner {
    position: relative;
    z-index: 1;
    -webkit-perspective: 1000;
    -moz-perspective: 1000;
    -ms-perspective: 1000;
    perspective: 1000;
    -ms-transform: perspective(1000px);
    -moz-transform: perspective(1000px);
    -moz-transform-style: preserve-3d;
    -ms-transform-style: preserve-3d;
}
.calendar-views {
    transform-style: preserve-3d;
}
.calendar .view {
    backface-visibility: hidden;
    position: absolute;
    top: 0;
    left: 0;
    *overflow: hidden;
    -webkit-transition: .6s;
    transition: .6s;
}
.calendar-d .view-month,
.calendar-m .view-date {
    transform: rotateY(180deg);
    visibility: hidden;
    z-index: 1;
}
.calendar-d .view-date,
.calendar-m .view-month {
    transform: rotateY(0deg);
    visibility: visible;
    z-index: 2;
}
.calendar-ct,
.calendar-hd,
.calendar-views .week,
.calendar-views .days {
    overflow: hidden;
}
.calendar-views {
    width: 100%;
}
.calendar .view,
.calendar-display,
.calendar-arrow .prev,
.calendar .date-items li {
    float: left;
}
.calendar-arrow,
.calendar-arrow .next {
    float: right;
}
.calendar-hd {
    padding: 10px 0;
    height: 30px;
    line-height: 30px;
}
.calendar-display {
    font-size: 28px;
    text-indent: 10px;
}
.view-month .calendar-hd {
    padding: 10px;
}
.calendar-arrow,
.calendar-display {
    color: #ddd;
}
.calendar li[disabled] {
    color: #bbb;
}
.calendar li.old[disabled],
.calendar li.new[disabled] {
    color: #eee;
}
.calendar-display .m,
.calendar-views .week,
.calendar-views .days .old,
.calendar-views .days .new,
.calendar-display:hover,
.calendar-arrow span:hover {
    color: #888;
}

.calendar-arrow span,
.calendar-views .days li[data-calendar-day],
.calendar-views .view-month li[data-calendar-month] {
    cursor: pointer;
} 
.calendar li[disabled] {
    cursor: not-allowed;
}

.calendar-arrow {
    width: 50px;
    margin-right: 10px;
}
.calendar-arrow span {
    font: 500 26px sans-serif;
}

.calendar ol li {
    position: relative;
    float: left;
    text-align: center;
    border-radius: 50%;
}
.calendar .week li,
.calendar .days li {
    width: 40px;
    height: 40px;
    line-height: 40px;
}
.calendar .month-items li {
    width: 70px;
    height: 70px;
    line-height: 70px;
}
.calendar .days li[data-calendar-day]:hover,
.calendar .view-month li[data-calendar-month]:hover {
    background: #eee; 
}
.calendar .calendar-views .now {
    color: #fff;
    background: #FF808E!important;  
}
.calendar .calendar-views .selected {
    color: #FF808E;
    background: #CDE9D9!important; 
}
.calendar .calendar-views .dot {
    position: absolute;
    left: 50%;
    bottom: 4px;
    margin-left: -2px; 
    width: 4px;
    height: 4px;
    background: #FF808E;
    border-radius: 50%;
}
.calendar-views .now .dot {
    background: #fff;
}

.calendar .date-items {
    width: 300%;
    margin-left: -100%;
}

.calendar-label {
    display: none;
    position: absolute;
    top: 50%;
    left: 50%;
    z-index: 2;
    padding: 5px 10px;
    line-height: 22px;
    color: #fff;
    background: #000;
    border-radius: 3px;
    opacity: .7;
    filter: alpha(opacity=70);
}
.calendar-label i {
    display: none;
    position: absolute;
    left: 50%;
    bottom: -12px;
    width: 0;
    height: 0;
    margin-left: -3px;
    border: 6px solid transparent;
    border-top-color: #000;
}


---calendar.js------------------------------------------------------------------------
(function(root, factory) {
    if (typeof define === 'function' && define.amd) {
        define('calendar', ['jquery'], factory);
    } else if (typeof exports === 'object') {
        module.exports = factory(require('jquery'));
    } else {
        factory(root.jQuery);
    }
}(this, function($) {

    // default config

    var defaults = {

            // 宽度
            width: 280,
            // 高度, 不包含头部,头部固定高度
            height: 280,

            zIndex: 1,

            // selector or element
            // 设置触发显示的元素,为null时默认显示
            trigger: null,

            // 偏移位置,可设正负值
            // trigger 设置时生效
            offset: [0, 1],

            // 自定义类,用于重写样式
            customClass: '',

            // 显示视图
            // 可选:date, month
            view: 'date',

            // 默认日期为当前日期
            date: new Date(),
            format: 'yyyy/mm/dd',

            // 一周的第一天
            // 0表示周日,依次类推
            startWeek: 0,

            // 星期格式
            weekArray: ['日', '一', '二', '三', '四', '五', '六'],

            // 设置选择范围
            // 格式:[开始日期, 结束日期]
            // 开始日期为空,则无上限;结束日期为空,则无下限
            // 如设置2015年11月23日以前不可选:[new Date(), null] or ['2015/11/23']
            selectedRang: null,

            // 日期关联数据 [{ date: string, value: object }, ... ]
            // 日期格式与 format 一致
            // 如 [ {date: '2015/11/23', value: '面试'} ]
            data: null,

            // 展示关联数据
            // 格式化参数:{m}视图,{d}日期,{v}value
            // 设置 false 表示不显示
            label: '{d}\n{v}',

            // 切换字符
            prev: '&lt;',
            next: '&gt;',

            // 切换视图
            // 参数:view, y, m
            viewChange: $.noop,

            // view: 视图
            // date: 不同视图返回不同的值
            // value: 日期关联数据
            onSelected: function(view, date, value) {
                // body...
            },

            // 参数同上
            onMouseenter: $.noop,

            onClose: $.noop
        },

        // static variable

        ACTION_NAMESPACE = 'data-calendar-',

        DISPLAY_VD = '[' + ACTION_NAMESPACE + 'display-date]',
        DISPLAY_VM = '[' + ACTION_NAMESPACE + 'display-month]',

        ARROW_DATE = '[' + ACTION_NAMESPACE + 'arrow-date]',
        ARROW_MONTH = '[' + ACTION_NAMESPACE + 'arrow-month]',

        ITEM_DAY = ACTION_NAMESPACE + 'day',
        ITEM_MONTH = ACTION_NAMESPACE + 'month',

        DISABLED = 'disabled',
        MARK_DATA = 'markData',

        VIEW_CLASS = {
            date: 'calendar-d',
            month: 'calendar-m'
        },

        OLD_DAY_CLASS = 'old',
        NEW_DAY_CLASS = 'new',
        TODAY_CLASS = 'now',
        SELECT_CLASS = 'selected',
        MARK_DAY_HTML = '<i class="dot"></i>',
        DATE_DIS_TPL = '{year}/<span class="m">{month}</span>',

        ITEM_STYLE = 'style="width:{w}px;height:{h}px;line-height:{h}px"',
        WEEK_ITEM_TPL = '<li ' + ITEM_STYLE + '>{wk}</li>',
        DAY_ITEM_TPL = '<li ' + ITEM_STYLE + ' class="{class}" {action}>{value}</li>',
        MONTH_ITEM_TPL = '<li ' + ITEM_STYLE + ' ' + ITEM_MONTH + '>{m}月</li>',

        TEMPLATE = [
            '<div class="calendar-inner">',
            '<div class="calendar-views">',
            '<div class="view view-date">',
            '<div class="calendar-hd">',
            '<a href="javascript:;" data-calendar-display-date class="calendar-display">',
            '{yyyy}/<span class="m">{mm}</span>',
            '</a>',
            '<div class="calendar-arrow">',
            '<span class="prev" title="上一月" data-calendar-arrow-date>{prev}</span>',
            '<span class="next" title="下一月" data-calendar-arrow-date>{next}</span>',
            '</div>',
            '</div>',
            '<div class="calendar-ct">',
            '<ol class="week">{week}</ol>',
            '<ul class="date-items"></ul>',
            '</div>',
            '</div>',
            '<div class="view view-month">',
            '<div class="calendar-hd">',
            '<a href="javascript:;" data-calendar-display-month class="calendar-display">{yyyy}</a>',
            '<div class="calendar-arrow">',
            '<span class="prev" title="上一年" data-calendar-arrow-month>{prev}</span>',
            '<span class="next" title="下一年" data-calendar-arrow-month>{next}</span>',
            '</div>',
            '</div>',
            '<ol class="calendar-ct month-items">{month}</ol>',
            '</div>',
            '</div>',
            '</div>',
            '<div class="calendar-label"><p>HelloWorld</p><i></i></div>'
        ],
        OS = Object.prototype.toString;

    // utils

    function isDate(obj) {
        return OS.call(obj) === '[object Date]';
    }

    function isString(obj) {
        return OS.call(obj) === '[object String]';
    }


    function getClass(el) {
        return el.getAttribute('class') || el.getAttribute('className');
    }

    // extension methods

    String.prototype.repeat = function(data) {
        return this.replace(/\{\w+\}/g, function(str) {
            var prop = str.replace(/\{|\}/g, '');
            return data[prop] || '';
        });
    }

    String.prototype.toDate = function() {
        var dt = new Date(),
            dot = this.replace(/\d/g, '').charAt(0),
            arr = this.split(dot);

        dt.setFullYear(arr[0]);
        dt.setMonth(arr[1] - 1);
        dt.setDate(arr[2]);
        return dt;
    }

    Date.prototype.format = function(exp) {
        var y = this.getFullYear(),
            m = this.getMonth() + 1,
            d = this.getDate();

        return exp.replace('yyyy', y).replace('mm', m).replace('dd', d);
    }

    Date.prototype.isSame = function(y, m, d) {
        if (isDate(y)) {
            var dt = y;
            y = dt.getFullYear();
            m = dt.getMonth() + 1;
            d = dt.getDate();
        }
        return this.getFullYear() === y && this.getMonth() + 1 === m && this.getDate() === d;
    }

    Date.prototype.add = function(n) {
        this.setDate(this.getDate() + n);
    }

    Date.prototype.minus = function(n) {
        this.setDate(this.getDate() - n);
    }

    Date.prototype.clearTime = function(n) {
        this.setHours(0);
        this.setSeconds(0);
        this.setMinutes(0);
        this.setMilliseconds(0);
        return this;
    }

    Date.isLeap = function(y) {
        return (y % 100 !== 0 && y % 4 === 0) || (y % 400 === 0);
    }

    Date.getDaysNum = function(y, m) {
        var num = 31;

        switch (m) {
            case 2:
                num = this.isLeap(y) ? 29 : 28;
                break;
            case 4:
            case 6:
            case 9:
            case 11:
                num = 30;
                break;
        }
        return num;
    }

    Date.getSiblingsMonth = function(y, m, n) {
        var d = new Date(y, m - 1);
        d.setMonth(m - 1 + n);
        return {
            y: d.getFullYear(),
            m: d.getMonth() + 1
        };
    }

    Date.getPrevMonth = function(y, m, n) {
        return this.getSiblingsMonth(y, m, 0 - (n || 1));
    }

    Date.getNextMonth = function(y, m, n) {
        return this.getSiblingsMonth(y, m, n || 1);
    }

    Date.tryParse = function(obj) {
        if (!obj) {
            return obj;
        }
        return isDate(obj) ? obj : obj.toDate();
    }


    // Calendar class

    function Calendar(element, options) {
        this.$element = $(element);
        this.options = $.extend({}, $.fn.calendar.defaults, options);
        this.$element.addClass('calendar ' + this.options.customClass);
        this.width = this.options.width;
        this.height = this.options.height;
        this.date = this.options.date;
        this.selectedRang = this.options.selectedRang;
        this.data = this.options.data;
        this.init();
    }

    Calendar.prototype = {
        constructor: Calendar,
        getDayAction: function(day) {
            var action = ITEM_DAY;
            if (this.selectedRang) {
                var start = Date.tryParse(this.selectedRang[0]),
                    end = Date.tryParse(this.selectedRang[1]);

                if ((start && day < start.clearTime()) || (end && day > end.clearTime())) {
                    action = DISABLED;
                }
            }

            return action;
        },
        getDayData: function(day) {
            var ret, data = this.data;

            if (data) {

                for (var i = 0, len = data.length; i < len; i++) {
                    var item = data[i];

                    if (day.isSame(item.date.toDate())) {
                        ret = item.value;
                    }
                }
            }

            return ret;
        },
        getDayItem: function(y, m, d, f) {
            var dt = this.date,
                idt = new Date(y, m - 1, d),
                data = {
                    w: this.width / 7,
                    h: this.height / 7,
                    value: d
                },
                markData,
                $item;

            var selected = dt.isSame(y, m, d) ? SELECT_CLASS : '';
            if (f === 1) {
                data['class'] = OLD_DAY_CLASS;
            } else if (f === 3) {
                data['class'] = NEW_DAY_CLASS;
            } else {
                data['class'] = '';
            }

            if (dt.isSame(y, m, d)) {
                data['class'] += ' ' + TODAY_CLASS;
            }

            data.action = this.getDayAction(idt);
            markData = this.getDayData(idt);

            $item = $(DAY_ITEM_TPL.repeat(data));

            if (markData) {
                $item.data(MARK_DATA, markData);
                $item.html(d + MARK_DAY_HTML);
            }

            return $item;
        },
        getDaysHtml: function(y, m) {
            var year, month, firstWeek, daysNum, prevM, prevDiff,
                dt = this.date,
                $days = $('<ol class="days"></ol>');

            if (isDate(y)) {
                year = y.getFullYear();
                month = y.getMonth() + 1;
            } else {
                year = Number(y);
                month = Number(m);
            }

            firstWeek = new Date(year, month - 1, 1).getDay() || 7;
            prevDiff = firstWeek - this.options.startWeek;
            daysNum = Date.getDaysNum(year, month);
            prevM = Date.getPrevMonth(year, month);
            prevDaysNum = Date.getDaysNum(year, prevM.m);
            nextM = Date.getNextMonth(year, month);
            // month flag
            var PREV_FLAG = 1,
                CURR_FLAG = 2,
                NEXT_FLAG = 3,
                count = 0;

            for (var p = prevDaysNum - prevDiff + 1; p <= prevDaysNum; p++, count++) {

                $days.append(this.getDayItem(prevM.y, prevM.m, p, PREV_FLAG));
            }

            for (var c = 1; c <= daysNum; c++, count++) {
                $days.append(this.getDayItem(year, month, c, CURR_FLAG));
            }

            for (var n = 1, nl = 42 - count; n <= nl; n++) {

                $days.append(this.getDayItem(nextM.y, nextM.m, n, NEXT_FLAG));
            }

            return $('<li></li>').width(this.options.width).append($days);
        },
        getWeekHtml: function() {
            var week = [],
                weekArray = this.options.weekArray,
                start = this.options.startWeek,
                len = weekArray.length,
                w = this.width / 7,
                h = this.height / 7;

            for (var i = start; i < len; i++) {
                week.push(WEEK_ITEM_TPL.repeat({
                    w: w,
                    h: h,
                    wk: weekArray[i]
                }));
            }

            for (var j = 0; j < start; j++) {
                week.push(WEEK_ITEM_TPL.repeat({
                    w: w,
                    h: h,
                    wk: weekArray[j]
                }));
            }

            return week.join('');
        },
        getMonthHtml: function() {
            var month = [],
                w = this.width / 4,
                h = this.height / 4,
                i = 1;

            for (; i < 13; i++) {
                month.push(MONTH_ITEM_TPL.repeat({
                    w: w,
                    h: h,
                    m: i
                }));
            }

            return month.join('');
        },
        setMonthAction: function(y) {
            var m = this.date.getMonth() + 1;

            this.$monthItems.children().removeClass(TODAY_CLASS);
            if (y === this.date.getFullYear()) {
                this.$monthItems.children().eq(m - 1).addClass(TODAY_CLASS);
            }
        },
        fillStatic: function() {
            var staticData = {
                prev: this.options.prev,
                next: this.options.next,
                week: this.getWeekHtml(),
                month: this.getMonthHtml()
            };

            this.$element.html(TEMPLATE.join('').repeat(staticData));
        },
        updateDisDate: function(y, m) {
            this.$disDate.html(DATE_DIS_TPL.repeat({
                year: y,
                month: m
            }));
        },
        updateDisMonth: function(y) {
            this.$disMonth.html(y);
        },
        fillDateItems: function(y, m) {
            var ma = [
                Date.getPrevMonth(y, m), {
                    y: y,
                    m: m
                },
                Date.getNextMonth(y, m)
            ];

            this.$dateItems.html('');
            for (var i = 0; i < 3; i++) {
                var $item = this.getDaysHtml(ma[i].y, ma[i].m);
                this.$dateItems.append($item);
            }

        },
        hide: function(view, date, data) {
            this.$trigger.val(date.format(this.options.format));
            this.options.onClose.call(this, view, date, data);
            this.$element.hide();
        },
        trigger: function() {

            this.$trigger = this.options.trigger instanceof $ ? this.options.trigger : $(this.options.trigger);

            var _this = this,
                $this = _this.$element,
                post = _this.$trigger.offset(),
                offs = _this.options.offset;

            $this.addClass('calendar-modal').css({
                left: (post.left + offs[0]) + 'px',
                top: (post.top + _this.$trigger.outerHeight() + offs[1]) + 'px',
                zIndex: _this.options.zIndex
            });

            _this.$trigger.click(function() {
                $this.show();
            });

            $(document).click(function(e) {
                if (_this.$trigger[0] != e.target && !$.contains($this[0], e.target)) {
                    $this.hide();
                }
            });
        },
        render: function() {
            this.$week = this.$element.find('.week');
            this.$dateItems = this.$element.find('.date-items');
            this.$monthItems = this.$element.find('.month-items');
            this.$label = this.$element.find('.calendar-label');
            this.$disDate = this.$element.find(DISPLAY_VD);
            this.$disMonth = this.$element.find(DISPLAY_VM);

            var y = this.date.getFullYear(),
                m = this.date.getMonth() + 1;

            this.updateDisDate(y, m);
            this.updateMonthView(y);

            this.fillDateItems(y, m);

            this.options.trigger && this.trigger();

        },
        setView: function(view) {
            this.$element.removeClass(VIEW_CLASS.date + ' ' + VIEW_CLASS.month)
                .addClass(VIEW_CLASS[view]);
            this.view = view;
        },
        updateDateView: function(y, m, dirc, cb) {
            m = m || this.date.getMonth() + 1;

            var _this = this,
                $dis = this.$dateItems,
                exec = {
                    prev: function() {
                        var pm = Date.getPrevMonth(y, m),
                            ppm = Date.getPrevMonth(y, m, 2),
                            $prevItem = _this.getDaysHtml(ppm.y, ppm.m);

                        m = pm.m;
                        y = pm.y;

                        $dis.animate({
                            marginLeft: 0
                        }, 300, 'swing', function() {
                            $dis.children(':last').remove();
                            $dis.prepend($prevItem).css('margin-left', '-100%');

                            $.isFunction(cb) && cb.call(_this);
                        });
                    },
                    next: function() {
                        var nm = Date.getNextMonth(y, m),
                            nnm = Date.getNextMonth(y, m, 2),
                            $nextItem = _this.getDaysHtml(nnm.y, nnm.m);

                        m = nm.m;
                        y = nm.y;

                        $dis.animate({
                            marginLeft: '-200%'
                        }, 300, 'swing', function() {
                            $dis.children(':first').remove();
                            $dis.append($nextItem).css('margin-left', '-100%');

                            $.isFunction(cb) && cb.call(_this);
                        });

                    }
                };


            if (dirc) {
                exec[dirc]();
            } else {
                this.fillDateItems(y, m);
            }

            this.updateDisDate(y, m);

            this.setView('date');

            return {
                y: y,
                m: m
            };
        },
        updateMonthView: function(y) {
            this.updateDisMonth(y);
            this.setMonthAction(y);
            this.setView('month');
        },
        getDisDateValue: function() {
            var arr = this.$disDate.html().split('/'),
                y = Number(arr[0]),
                m = Number(arr[1].match(/\d{1,2}/)[0]);

            return [y, m];
        },
        selectedDay: function(d, type) {
            var arr = this.getDisDateValue(),
                y = arr[0],
                m = arr[1],
                toggleClass = function() {
                    this.$dateItems.children(':eq(1)')
                        .find('[' + ITEM_DAY + ']:not(.' + NEW_DAY_CLASS + ', .' + OLD_DAY_CLASS + ')')
                        .removeClass(SELECT_CLASS)
                        .filter(function(index) {
                            return parseInt(this.innerHTML) === d;
                        }).addClass(SELECT_CLASS);
                };

            if (type) {
                var ret = this.updateDateView(y, m, {
                    'old': 'prev',
                    'new': 'next'
                }[type], toggleClass);
                y = ret.y;
                m = ret.m;
                this.options.viewChange('date', y, m);
            } else {
                toggleClass.call(this);
            }

            return new Date(y, m - 1, d);
        },
        showLabel: function(event, view, date, data) {
            var $lbl = this.$label;

            $lbl.find('p').html(this.options.label.repeat({
                m: view,
                d: date.format(this.options.format),
                v: data
            }).replace(/\n/g, '<br>'));

            var w = $lbl.outerWidth(),
                h = $lbl.outerHeight();

            $lbl.css({
                left: (event.pageX - w / 2) + 'px',
                top: (event.pageY - h - 20) + 'px'
            }).show();
        },
        hasLabel: function() {
            if (this.options.label) {
                $('body').append(this.$label);
                return true;
            }
            return false;
        },
        event: function() {
            var _this = this,
                vc = _this.options.viewChange;

            // view change
            _this.$element.on('click', DISPLAY_VD, function() {
                var arr = _this.getDisDateValue();
                _this.updateMonthView(arr[0], arr[1]);

                vc('month', arr[0], arr[1]);

            }).on('click', DISPLAY_VM, function() {
                var y = this.innerHTML;

                _this.updateDateView(y);
                vc('date', y);
            });

            // arrow
            _this.$element.on('click', ARROW_DATE, function() {
                var arr = _this.getDisDateValue(),
                    type = getClass(this),
                    y = arr[0],
                    m = arr[1];

                var d = _this.updateDateView(y, m, type, function() {
                    vc('date', d.y, d.m);
                });

            }).on('click', ARROW_MONTH, function() {

                var y = Number(_this.$disMonth.html()),
                    type = getClass(this);

                y = type === 'prev' ? y - 1 : y + 1;
                _this.updateMonthView(y);
                vc('month', y);
            });

            // selected
            _this.$element.on('click', '[' + ITEM_DAY + ']', function() {
                var d = parseInt(this.innerHTML),
                    cls = getClass(this),
                    type = /new|old/.test(cls) ? cls.match(/new|old/)[0] : '';

                var day = _this.selectedDay(d, type);

                _this.options.onSelected.call(this, 'date', day, $(this).data(MARK_DATA));

                _this.$trigger && _this.hide('date', day, $(this).data(MARK_DATA));

            }).on('click', '[' + ITEM_MONTH + ']', function() {
                var y = Number(_this.$disMonth.html()),
                    m = parseInt(this.innerHTML);

                _this.updateDateView(y, m);
                vc('date', y, m);
                _this.options.onSelected.call(this, 'month', new Date(y, m - 1));
            });

            // hover
            _this.$element.on('mouseenter', '[' + ITEM_DAY + ']', function(e) {
                var arr = _this.getDisDateValue(),
                    day = new Date(arr[0], arr[1] - 1, parseInt(this.innerHTML));

                if (_this.hasLabel && $(this).data(MARK_DATA)) {
                    $('body').append(_this.$label);
                    _this.showLabel(e, 'date', day, $(this).data(MARK_DATA));
                }

                _this.options.onMouseenter.call(this, 'date', day, $(this).data(MARK_DATA));
            }).on('mouseleave', '[' + ITEM_DAY + ']', function() {
                _this.$label.hide();
            });
        },
        resize: function() {
            var w = this.width,
                h = this.height,
                hdH = this.$element.find('.calendar-hd').outerHeight();

            this.$element.width(w).height(h + hdH)
                .find('.calendar-inner, .view')
                .css('width', w + 'px');

            this.$element.find('.calendar-ct').width(w).height(h);

        },
        init: function() {

            this.fillStatic();
            this.resize();
            this.render();
            this.view = this.options.view;
            this.setView(this.view);
            this.event();
        },
        setData: function(data) {
            this.data = data;

            if (this.view === 'date') {
                var d = this.getDisDateValue();
                this.fillDateItems(d[0], d[1]);
            } else if (this.view === 'month') {
                this.updateMonthView(this.$disMonth.html());
            }
        },
        methods: function(name, args) {
            if (OS.call(this[name]) === '[object Function]') {
                return this[name].apply(this, args);
            }
        }
    };

    $.fn.calendar = function(options) {
        var calendar = this.data('calendar'),
            fn,
            args = [].slice.call(arguments);

        if (!calendar) {
            return this.each(function() {
                return $(this).data('calendar', new Calendar(this, options));
            });
        }
        if (isString(options)) {
            fn = options;
            args.shift();
            return calendar.methods(fn, args);
        }

        return this;
    }

    $.fn.calendar.defaults = defaults;

}));






# xiaoxiao [ 2016-05-30 ]

# Address in this article

# http://www.s7smile.com/javascript/13

# s7smile.com