-2

绝对位置在 Mozilla 中不起作用。对于 jquery 日历,我将 position:absolute 用于 div,它似乎除了 windows 中的 mozilla 之外都可以工作。当我删除 position:absolute 时,它​​将在 windows firefox 中工作,但在所有其他浏览器中仅显示备用月份

jQuery是

var CalendarEightysix = new Class({
    Implements: Options,

    options: {
        'slideDuration': 500,
        'fadeDuration': 200,
        'toggleDuration': 200,
        'fadeTransition': Fx.Transitions.linear,
        'slideTransition': Fx.Transitions.Quart.easeOut,

        'prefill': true,
        'defaultDate': null,
        'linkWithInput': true,

        'theme': 'default',
        'defaultView': 'month',
        'startMonday': false,
        'alwaysShow': false,
        'injectInsideTarget': false,
        'format': '%n/%d/%Y',
        'alignX': 'right',
        'alignY': 'ceiling',
        'offsetX': 0,
        'offsetY': 0,

        'draggable': false,
        'pickable': true,
        'toggler': null,
        'pickFunction': $empty,
        'disallowUserInput': false,

        'minDate': null,
        'maxDate': null,
        'excludedWeekdays': null,
        'excludedDates': null,

        'createHiddenInput': false,
        'hiddenInputName': 'date',
        'hiddenInputFormat': '%t'
    },

    initialize: function(target, options) {
        this.setOptions(options);

        this.target = $(target);
        this.transitioning = false;

        //Extend Date with unix timestamp parser
        Date.defineParser({
            re: /^[0-9]{10}$/,
            handler: function(bits) { return new Date.parse('Jan 01 1970').set('seconds', bits[0]); }
        });

        //Selected date
        if($defined(this.options.defaultDate)) this.selectedDate = new Date().parse(this.options.defaultDate).clearTime();
        else if(this.options.linkWithInput && $chk(this.target.get('value'))) this.selectedDate = new Date().parse(this.target.get('value')).clearTime();
        if(!$defined(this.selectedDate) || !this.selectedDate.isValid()) this.selectedDate = new Date();
        this.viewDate = this.selectedDate.clone().set('date', 1).clearTime();

        //Base
        var innerHtml = '<div class="wrapper"><div class="header"><div class="arrow-left"></div><div class="arrow-right"></div><div class="label clickable"></div></div>'+
                            '<div class="body"><div class="inner"><div class="container a"></div><div class="container b"></div></div></div><div class="footer"></div></div>';
        this.element = new Element('div', { 'class': 'calendar-eightysix', 'html': innerHtml, 'style': 'display: '+ (this.options.alwaysShow ? 'block' : 'none') }).addClass(this.options.theme);

        if(this.options.injectInsideTarget) this.element.injectBottom(this.target);
        else {
            this.element.injectBottom($(document.body));
            this.position();
            window.addEvent('resize', this.position.bind(this));
        }

        this.currentContainer = this.element.getElement('.container.a').setStyle('z-index', 999);
        this.tempContainer = this.element.getElement('.container.b').setStyle('z-index', 998);

        //Header
        this.header = this.element.getElement('.header');
        this.label = this.header.getElement('.label');
        this.arrowLeft = this.header.getElement('.arrow-left');
        this.arrowRight = this.header.getElement('.arrow-right');

        this.label.addEvent('click', this.levelUp.bind(this));
        this.arrowLeft.addEvent('click', this.slideLeft.bind(this));
        this.arrowRight.addEvent('click', this.slideRight.bind(this));

        //Date range
        if($defined(this.options.minDate)) {
            this.options.minDate = Date.parse(this.options.minDate).clearTime();
            if(!this.options.minDate.isValid()) this.options.minDate = null;
        }
        if($defined(this.options.maxDate)) {
            this.options.maxDate = Date.parse(this.options.maxDate).clearTime();
            if(!this.options.maxDate.isValid()) this.options.maxDate = null;
        }

        //Excluded dates
        if($defined(this.options.excludedDates)) {
            var excludedDates = [];
            this.options.excludedDates.each(function(date) {
                excludedDates.include(this.format(new Date().parse(date).clearTime(), '%t'));
            }.bind(this));
            this.options.excludedDates = excludedDates;
        }

        //Dragger
        if(this.options.draggable && !this.options.injectInsideTarget) {
            this.header.addClass('dragger');
            new Drag(this.element, { 'handle': this.header });
        }

        //Hidden input
        if(this.options.createHiddenInput) {
            this.hiddenInput = new Element('input', { 'type': 'hidden', 'name': this.options.hiddenInputName }).injectAfter(this.target);
        }

        //Prefill date
        if(this.options.prefill) this.pick();

        //Link with input
        if(!this.options.disallowUserInput && this.options.linkWithInput && this.target.get('tag') == 'input') {
            this.target.addEvent('keyup', function() {
                this.setDate(this.target.get('value'), false);
            }.bind(this));
        }

        //Disallow input
        if(this.options.disallowUserInput && this.target.get('tag') == 'input') 
            this.target.addEvents({ 'keydown': ($lambda(false)), 'contextmenu': ($lambda(false)) });

        //Toggler
        if($defined(this.options.toggler)) this.options.toggler = $(this.options.toggler);

        //Show / hide events
        ($defined(this.options.toggler) ? this.options.toggler : this.target).addEvents({
            'focus': this.show.bind(this), 'click': this.show.bind(this)
        });

        if(!this.options.alwaysShow) document.addEvent('mousedown', this.outsideClick.bind(this));
        MooTools.lang.addEvent('langChange', function() { this.render(); this.pick(); }.bind(this));

        //View
        this.view = this.options.defaultView;
        this.render();
    },

    render: function() {
        this.currentContainer.empty();

        switch(this.view) {
            case 'decade': this.renderDecade(); break;
            case 'year': this.renderYear(); break;
            default: this.renderMonth();
        }
    },

    renderMonth: function() {
        this.view = 'month';
        this.currentContainer.empty().addClass('month');
        if(this.options.pickable) this.currentContainer.addClass('pickable');

        var lang = MooTools.lang.get('Date'), weekdaysCount = this.viewDate.format('%w') - (this.options.startMonday ? 1 : 0);
        if(weekdaysCount == -1) weekdaysCount = 6;
        var today = new Date();

        //Label
        this.label.set('html', lang.months[this.viewDate.get('month')] +' '+ this.viewDate.format('%Y'));

        //Day label row
        var row = new Element('div', { 'class': 'row' }).injectBottom(this.currentContainer);
        for(var i = (this.options.startMonday ? 1 : 0); i < (this.options.startMonday ? 8 : 7); i++) {
            var day = new Element('div', { 'html': lang.days[this.options.startMonday && i == 7 ? 0 : i] }).injectBottom(row);
            day.set('html', day.get('html').substr(0, 2));
        }

        //Add days for the beginning non-month days
        row = new Element('div', { 'class': 'row' }).injectBottom(this.currentContainer);
        y = this.viewDate.clone().decrement('month').getLastDayOfMonth();
        for(var i = 0; i < weekdaysCount; i++) {
            this.injectDay(row, this.viewDate.clone().decrement('month').set('date', y - (weekdaysCount - i) + 1), true);
        }

        //Add month days
        for(var i = 1; i <= this.viewDate.getLastDayOfMonth(); i++) {
            this.injectDay(row, this.viewDate.clone().set('date', i));
            if(row.getChildren().length == 7) {
                row = new Element('div', { 'class': 'row' }).injectBottom(this.currentContainer);
            }
        }

        //Add outside days
        var y = 8 - row.getChildren().length, startDate = this.viewDate.clone().increment('month').set('date', 1);
        for(var i = 1; i < y; i++) {
            this.injectDay(row, startDate.clone().set('date', i), true);
        }

        //Always have six rows
        for(var y = this.currentContainer.getElements('.row').length; y < 7; y++) {
            row = new Element('div', { 'class': 'row' }).injectBottom(this.currentContainer);
            for(var z = 0; z < 7; z++) {
                this.injectDay(row, startDate.clone().set('date', i), true);
                i++;
            }
        }

        this.renderAfter();
    },

    //Used by renderMonth
    injectDay: function(row, date, outside) {
        today = new Date();

        var day = new Element('div', { 'html': date.get('date') }).injectBottom(row);
        day.date = date;
        if(outside) day.addClass('outside');

        if(($defined(this.options.minDate) && this.format(this.options.minDate, '%t') > this.format(date, '%t')) || 
           ($defined(this.options.maxDate) && this.format(this.options.maxDate, '%t') < this.format(date, '%t')) ||
           ($defined(this.options.excludedWeekdays) && this.options.excludedWeekdays.contains(date.format('%w').toInt())) ||
           ($defined(this.options.excludedDates) && this.options.excludedDates.contains(this.format(date, '%t'))))
            day.addClass('non-selectable');
        else if(this.options.pickable) day.addEvent('click', this.pick.bind(this));

        if(date.format('%x') == today.format('%x')) day.addClass('today');
        if(date.format('%x') == this.selectedDate.format('%x')) day.addClass('selected');
    },

    renderYear: function() {
        this.view = 'year';
        this.currentContainer.addClass('year-decade');
        var today = new Date(), lang = MooTools.lang.get('Date').months;

        //Label
        this.label.set('html', this.viewDate.format('%Y'));

        var row = new Element('div', { 'class': 'row' }).injectBottom(this.currentContainer);
        for(var i = 1; i < 13; i++) {
            var month = new Element('div', { 'html': lang[i - 1] }).injectBottom(row);
            month.set('html', month.get('html').substr(0, 3));  //Setting and getting the innerHTML takes care of html entity problems (e.g. [M&a]uml;r => [Mär]z)
            var iMonth = this.viewDate.clone().set('month', i - 1);
            month.date = iMonth;

            if(($defined(this.options.minDate) && this.format(this.options.minDate.clone().set('date', 1), '%t') > this.format(iMonth, '%t')) ||
               ($defined(this.options.maxDate) && this.format(this.options.maxDate.clone().set('date', 1), '%t') < this.format(iMonth, '%t')))
                month.addClass('non-selectable');
            else month.addEvent('click', this.levelDown.bind(this));

            if(i - 1 == today.get('month') && this.viewDate.get('year') == today.get('year')) month.addClass('today');
            if(i - 1 == this.selectedDate.get('month') && this.viewDate.get('year') == this.selectedDate.get('year')) month.addClass('selected');
            if(!(i % 4) && i != 12) row = new Element('div', { 'class': 'row' }).injectBottom(this.currentContainer);
        }

        this.renderAfter();
    },

    renderDecade: function() {
        this.label.removeClass('clickable');
        this.view = 'decade';
        this.currentContainer.addClass('year-decade');
        var today = new Date();

        var viewYear, startYear;
        viewYear = startYear = this.viewDate.format('%Y').toInt();
        while(startYear % 12) startYear--;

        //Label
        this.label.set('html', startYear +' &#150; '+ (startYear + 11));

        var row = new Element('div', { 'class': 'row' }).injectBottom(this.currentContainer);
        for(var i = startYear; i < startYear + 12; i++) {
            var year = new Element('div', { 'html': i }).injectBottom(row);
            var iYear = this.viewDate.clone().set('year', i);
            year.date = iYear;

            if(($defined(this.options.minDate) && this.options.minDate.get('year') > i) ||
               ($defined(this.options.maxDate) && this.options.maxDate.get('year') < i)) year.addClass('non-selectable');
            else year.addEvent('click', this.levelDown.bind(this));

            if(i == today.get('year')) year.addClass('today');
            if(i == this.selectedDate.get('year')) year.addClass('selected');
            if(!((i + 1) % 4) && i != startYear + 11) row = new Element('div', { 'class': 'row' }).injectBottom(this.currentContainer);
        }

        this.renderAfter();
    },

    renderAfter: function() {
        //Iterate rows and add classes and remove navigation if nessesary
        var rows = this.currentContainer.getElements('.row');
        for(var i = 0; i < rows.length; i++) {
            rows[i].set('class', 'row '+ ['a', 'b', 'c', 'd', 'e', 'f', 'g'][i] +' '+ (i % 2 ? 'even' : 'odd')).getFirst().addClass('first');
            rows[i].getLast().addClass('last');

            if(i == (this.view == 'month' ? 1 : 0) && $defined(this.options.minDate) && this.format(this.options.minDate, '%t') >= this.format(rows[i].getFirst().date, '%t')) 
                this.arrowLeft.setStyle('visibility', 'hidden');
            if(i == rows.length - 1 && $defined(this.options.maxDate)) {
                if((this.view == 'month' && this.format(this.options.maxDate, '%t') <= this.format(rows[i].getLast().date, '%t')) ||
                   (this.view == 'year' && this.format(this.options.maxDate, '%t') <= this.format(rows[i].getLast().date.clone().increment('month'), '%t')) ||
                   (this.view == 'decade' && this.format(this.options.maxDate, '%t') <= this.format(rows[i].getLast().date.clone().increment('year'), '%t')))
                    this.arrowRight.setStyle('visibility', 'hidden');
            }
        };
    },

    slideLeft: function() {
        this.switchContainers();

        //Render new view
        switch(this.view) {
            case 'month':  this.viewDate.decrement('month'); break;
            case 'year':   this.viewDate.decrement('year'); break;
            case 'decade': this.viewDate.set('year', this.viewDate.get('year') - 12); break;
        }
        this.render();

        //Tween the new view in and old view out
        this.currentContainer.set('tween', { 'duration': this.options.slideDuration, 'transition': this.options.slideTransition }).tween('left', [-this.currentContainer.getWidth(), 0]);
        this.tempContainer.set('tween', { 'duration': this.options.slideDuration, 'transition': this.options.slideTransition }).tween('left', [0, this.tempContainer.getWidth()]);
    },

    slideRight: function() {
        this.switchContainers();

        //Render new view
        switch(this.view) {
            case 'month':  this.viewDate.increment('month'); break;
            case 'year':   this.viewDate.increment('year'); break;
            case 'decade': this.viewDate.set('year', this.viewDate.get('year') + 12); break;
        }
        this.render();

        //Tween the new view in and old view out
        this.currentContainer.set('tween', { 'duration': this.options.slideDuration, 'transition': this.options.slideTransition }).tween('left', [this.currentContainer.getWidth(), 0]);
        this.tempContainer.set('tween', { 'duration': this.options.slideDuration, 'transition': this.options.slideTransition }).tween('left', [0, -this.currentContainer.getWidth()]);
    },

    levelDown: function(e) {
        if(this.transitioning) return;
        this.switchContainers();
        this.viewDate = e.target.date;

        //Render new view
        switch(this.view) {
            case 'year': this.renderMonth(); break;
            case 'decade': this.renderYear(); break;
        }

        //Tween the new view in and old view out
        this.transitioning = true;
        this.currentContainer.set('tween', { 'duration': this.options.fadeDuration, 'transition': this.options.fadeTransition, 
                                             'onComplete': function() { this.transitioning = false }.bind(this) }).setStyles({'opacity': 0, 'left': 0}).fade('in');
        this.tempContainer.set('tween', { 'duration': this.options.fadeDuration, 'transition': this.options.fadeTransition }).fade('out');
    },

    levelUp: function() {
        if(this.view == 'decade' || this.transitioning) return;
        this.switchContainers();

        //Set viewdates and render
        switch(this.view) {
            case 'month': this.renderYear(); break;
            case 'year':  this.renderDecade(); break;
        }

        //Tween the new view in and old view out
        this.transitioning = true;
        this.currentContainer.set('tween', { 'duration': this.options.fadeDuration, 'transition': this.options.fadeTransition, 
                                             'onComplete': function() { this.transitioning = false }.bind(this) }).setStyles({'opacity': 0, 'left': 0}).fade('in');
        this.tempContainer.set('tween', { 'duration': this.options.fadeDuration, 'transition': this.options.fadeTransition }).fade('out');
    },

    switchContainers: function() {
        this.currentContainer = this.currentContainer.hasClass('a') ? this.element.getElement('.container.b') : this.element.getElement('.container.a');
        this.tempContainer = this.tempContainer.hasClass('a') ? this.element.getElement('.container.b') : this.element.getElement('.container.a');
        this.currentContainer.empty().removeClass('month').removeClass('year-decade').setStyles({ 'opacity': 1, 'display': 'block', 'z-index': 999 });
        this.tempContainer.setStyle('z-index', 998);

        this.label.addClass('clickable');
        this.arrowLeft.setStyle('visibility', 'visible');
        this.arrowRight.setStyle('visibility', 'visible');
    },

    pick: function(e) {
        if($defined(e)) {
            this.selectedDate = e.target.date;
            this.element.getElements('.selected').removeClass('selected');
            e.target.addClass('selected');
        }

        var value = this.format(this.selectedDate);

        if(!this.options.injectInsideTarget) {
            switch(this.target.get('tag')) {
                case 'input': this.target.set('value', value); break;
                default: this.target.set('html', value);
            }
            (this.hide.bind(this)).delay(150);
        }

        if($defined(this.hiddenInput)) this.hiddenInput.set('value', this.format(this.selectedDate, this.options.hiddenInputFormat));
        this.options.pickFunction(this.selectedDate);
    },

    position: function() {
        var top, left;
        var coordinates = this.target.getCoordinates();

        switch(this.options.alignX) {
            case 'left':
                left = coordinates.left;
                break;
            case 'middle':
                left = coordinates.left + (coordinates.width / 2) - (this.element.getWidth() / 2);
                break;
            case 'right': default:
                left = coordinates.left + coordinates.width;
        }

        switch(this.options.alignY) {
            case 'bottom':
                top = coordinates.top + coordinates.height;
                break;
            case 'top':
                top = coordinates.top - this.element.getHeight();
                break;
            case 'ceiling': default:
                top = coordinates.top;
        }

        left += this.options.offsetX.toInt();
        top += this.options.offsetY.toInt();

        this.element.setStyles({ 'top': top, 'left': left });
    },

    show: function() {
        if(!this.visible & !this.options.alwaysShow) {
            this.visible = true;
            if(!Browser.Engine.trident) {
                this.element.setStyles({ 'opacity': 0, 'display': 'block' });
                if(!this.options.injectInsideTarget) this.position();
                this.element.set('tween', { 'duration': this.options.toggleDuration, 'transition': this.options.fadeTransition }).fade('in');
            }  else {
                this.element.setStyles({ 'opacity': 1, 'display': 'block' });
                if(!this.options.injectInsideTarget) this.position();
            }
        }
    },

    hide: function() {
        if(this.visible & !this.options.alwaysShow) {
            this.visible = false;
            if(!Browser.Engine.trident) {
                this.element.set('tween', { 'duration': this.options.toggleDuration, 'transition': this.options.fadeTransition,
                                            'onComplete': function() { this.element.setStyle('display', 'none') }.bind(this) }).fade('out');
            } else this.element.setStyle('display', 'none');
        }
    },

    toggle: function() {
        if(this.visible) this.hide();
        else this.show();
    },

    format: function(date, format) {
        if(!$defined(format)) format = this.options.format;
        if(!$defined(date)) return;
        format = format.replace(/%([a-z%])/gi,
            function($1, $2) {
                switch($2) {
                    case 'D': return date.get('date');
                    case 'n': return date.get('mo') + 1;
                    case 't': return (date.getTime() / 1000).toInt();
                }
                return '%'+ $2;
            }
        );
        return date.format(format);
    },

    outsideClick: function(e) {
        if(this.visible) {
            var elementCoords = this.element.getCoordinates();
            var targetCoords  = this.target.getCoordinates();
            if(((e.page.x < elementCoords.left || e.page.x > (elementCoords.left + elementCoords.width)) ||
                (e.page.y < elementCoords.top  || e.page.y > (elementCoords.top + elementCoords.height))) &&
               ((e.page.x < targetCoords.left  || e.page.x > (targetCoords.left + targetCoords.width)) ||
                (e.page.y < targetCoords.top   || e.page.y > (targetCoords.top + targetCoords.height))) ) this.hide();
        }
    },

    //Version 1.0.1 addition, can easily be called from outside
    setDate: function(value, pick) {
        if(!$defined(pick)) pick = true;
        if($type(value) == 'date') {
            var date = value.clearTime();
        } else {
            var date = $chk(value) ? new Date().parse(this.target.get('value')).clearTime() : new Date().clearTime();
        }
        if(date.isValid()) {
            this.selectedDate = date.clone();
            this.viewDate = this.selectedDate.clone().set('date', 1);
            this.render();
            if(pick) this.pick();
        }
    }
});

Style.css 是

        .calendar-eightysix .body {
            position: relative;
        }
            .calendar-eightysix .body .inner .container {
                position: absolute;
                left: 0;
            }
4

1 回答 1

0

在 jquery 中,将 switchContainers: function() 替换为

switchContainers: function() {
    this.currentContainer = this.currentContainer.hasClass('a') ? this.element.getElement('.container.b') : this.element.getElement('.container.a');
    this.tempContainer = this.tempContainer.hasClass('a') ? this.element.getElement('.container.b') : this.element.getElement('.container.a');
    this.currentContainer.empty().removeClass('month').removeClass('year-decade').setStyles({ 'opacity': 1, 'display': 'block', 'z-index': 999 });
    this.tempContainer.setStyles({ 'display': 'none', 'z-index': 998 });
    this.currentContainer.hasClass('a') ? this.currentContainer.setStyles({ 'opacity': 1, 'display': 'block', 'z-index': 999 }) : '';

    this.label.addClass('clickable');
    this.arrowLeft.setStyle('visibility', 'visible');
    this.arrowRight.setStyle('visibility', 'visible');
},

在 style.css 中替换.calendar-eightysix .body .inner .container

.calendar-eightysix .body .inner .container {
    left: 0;
}
于 2013-01-18T11:51:40.637 回答