2015-06-17 103 views
0

我试图创建一个简单的jQuery插件,允许多个“timepicker”实例。过去我没有做过很多JavaScript OOP,所以我认为创建这个对我来说是一个很好的学习体验。这就是说,我似乎无法弄清楚为什么当我改变时间时,所有实例都会受到影响。这是我在StackOverflow上的第一篇文章,请耐心等待。 下面的代码:jquery插件多个实例

(function($) { 
 

 
    //Helper functions 
 
    if (typeof String.prototype.endsWith != 'function') { 
 
    String.prototype.endsWith = function(str) { 
 
     return str.length > 0 && this.substring(this.length - str.length, this.length) === str; 
 
    } 
 
    } 
 

 
    //Find if area is on the clickable list 
 
    var findOne = function(haystack, arr) { 
 
    return arr.some(function(v) { 
 
     return haystack.indexOf(v) >= 0; 
 
    }); 
 
    }; 
 

 
    var Timepicker = function(element, options) { 
 

 
    this.defaults = { 
 
     now: new Date() 
 
    }; 
 
    this.element = $(element); 
 
    this.createTimepicker(); 
 
    this.options = $.extend({}, this.defaults, options); 
 
    this.timepicker = $('.wicked-picker'); //The outer portion of the picker 
 
    this.up = $('.wicked-picker__controls__control-up'); //the up control(s) 
 
    this.down = $('.wicked-picker__controls__control-down'); //the down control(s) 
 
    this.hoursElem = $('.wicked-picker__controls__control--hours'); //the hours text 
 
    this.minutesElem = $('.wicked-picker__controls__control--minutes'); //the minutes text 
 
    this.meridiemElem = $('.wicked-picker__controls__control--meridiem'); //the am or pm text 
 
    this.canClick = ['timepicker', this.timepicker.selector.substring(1), this.up.selector.substring(1), this.down.selector.substring(1), this.hoursElem.selector.substring(1), this.minutesElem.selector.substring(1), this.meridiemElem.selector.substring(1)]; //the clickable areas 
 
    this.selectedHour = ((this.defaults.now.getHours() + 11) % 12) + 1; //the default hour 
 
    this.selectedMin = ((this.defaults.now.getMinutes() < 10) ? '0' : '') + this.defaults.now.getMinutes(); //the default minute 
 
    this.selectedMeridiem = (this.defaults.now.getHours > 12) ? 'PM' : 'AM'; //the defaut meridiem 
 
    this.attach(element); //attach events to this element 
 

 
    }; 
 

 
    $.extend(Timepicker.prototype = { 
 

 
    showTimepicker: function(element) { 
 
     var timepickerPos = this.element.offset(); 
 
     //set time to default time (now) 
 
     this.setText(element); 
 
     //if the timepicker's time differs from the input field's time change it 
 
     if (this.getText(element) !== this.getTime()) { 
 
     var inputTime = this.getText(element).replace(':', '').split(' '); 
 
     var newTime = new Date(); 
 
     newTime.setHours(inputTime[0]); 
 
     newTime.setMinutes(inputTime[2]); 
 
     this.setTime(newTime); 
 
     } 
 
     //Positioning 
 
     this.timepicker.css({ 
 
     'z-index': this.element.zIndex() + 1, 
 
     position: 'absolute', 
 
     left: timepickerPos.left, 
 
     top: timepickerPos.top + element.target.offsetHeight + 5 
 
     }).show(); 
 

 
     //Time up/down events 
 
     //Most likely the area with issues 
 
     //Needs to know which instance 
 
     $(this.up).on('click', $.proxy(this.changeValue, this, '+', element)); 
 
     $(this.down).on('click', $.proxy(this.changeValue, this, '-', element)); 
 
    }, 
 

 
    hideTimepicker: function(element) { 
 
     var targetClass = element.target.className.split(' '); 
 
     //Check if area is clickable before hiding 
 
     if (findOne(targetClass, this.canClick) === false) { 
 
     this.timepicker.hide(); 
 
     } 
 
    }, 
 

 
    //Create only one timepicker per page 
 
    createTimepicker: function() { 
 
     if ($('.wicked-picker').length === 0) 
 
     $('body').append('<div class="wicked-picker"> <p class="wicked-picker__title">Timepicker</p> <ul class="wicked-picker__controls"> <li class="wicked-picker__controls__control"> <span class="wicked-picker__controls__control-up"></span><span class="wicked-picker__controls__control--hours">00</span><span class="wicked-picker__controls__control-down"></span> </li> <li class="wicked-picker__controls__control"> <span class="wicked-picker__controls__control-up"></span><span class="wicked-picker__controls__control--minutes">00</span><span class="wicked-picker__controls__control-down"></span> </li> <li class="wicked-picker__controls__control"> <span class="wicked-picker__controls__control-up"></span><span class="wicked-picker__controls__control--meridiem">AM</span><span class="wicked-picker__controls__control-down"></span> </li> </ul> </div>'); 
 
    }, 
 

 
    //Attach the show and hide picker events 
 
    attach: function(element) { 
 
     $(element).on('focus', $.proxy(this.showTimepicker, this)); 
 
     $('body').on('click', $.proxy(this.hideTimepicker, this)); 
 
    }, 
 

 
    //set the timepicker's time 
 
    setTime: function(time) { 
 
     this.setHours(time.getHours()); 
 
     this.setMinutes(time.getMinutes()); 
 
     this.setMeridiem(); 
 
    }, 
 

 
    //get the timepicker's time in the form H : MM : AM || PM 
 
    getTime: function() { 
 
     return [this.getHours + ' : ' + this.getMinutes() + ' ' + this.getMeridiem()]; 
 
    }, 
 

 
    //set the timepicker's and input field's hours 
 
    setHours: function(hours) { 
 
     var hour = new Date(); 
 
     hour.setHours(hours); 
 
     var hoursText = ((hour.getHours() + 11) % 12) + 1; 
 
     this.hoursElem.text(hoursText); 
 
     this.selectedHour = hoursText; 
 
    }, 
 

 
    //set the timepicker's hours 
 
    getHours: function() { 
 
     var hours = new Date(); 
 
     hours.setHours(this.hoursElem.text()); 
 
     return hours.getHours(); 
 
    }, 
 

 
    //set the timepicker's and input field's minutes 
 
    setMinutes: function(minutes) { 
 
     var minute = new Date(); 
 
     minute.setMinutes(minutes); 
 
     var minutesText = minute.getMinutes(); 
 
     var min = ((minutesText < 10) ? '0' : '') + minutesText; 
 
     this.minutesElem.text(min); 
 
     this.selectedMin = min; 
 
    }, 
 

 
    //set the timepicker's minutes 
 
    getMinutes: function() { 
 
     var minutes = new Date(); 
 
     minutes.setMinutes(this.minutesElem.text()); 
 
     var minutesText = minutes.getMinutes(); 
 
     return ((minutesText < 10) ? '0' : '') + minutesText; 
 
    }, 
 

 
    //set the timepicker's and input field's meridiem 
 
    setMeridiem: function() { 
 
     var meridiem = this.getMeridiem(); 
 
     var newMeridiem = (meridiem === 'PM') ? 'AM' : 'PM'; 
 
     this.meridiemElem.text(newMeridiem); 
 
     this.selectedMeridiem = newMeridiem; 
 
    }, 
 

 
    //set the timepicker's meridiem 
 
    getMeridiem: function() { 
 
     return this.meridiemElem.text(); 
 
    }, 
 

 
    //change the input field's time based on the arrow selected for each time unit 
 
    //input is the input field to be changed 
 
    //element is the up or down arrow clicked 
 
    //operator is the '+' or '-' sign 
 
    changeValue: function(operator, input, element) { 
 
     var target = (operator === '+') ? element.target.nextSibling : element.target.previousSibling; 
 
     var targetClass = $(target).attr('class'); 
 
     if (targetClass.endsWith('hours')) { 
 
     this.setHours(eval(this.getHours() + operator + 1)); 
 
     } else if (targetClass.endsWith('minutes')) { 
 
     this.setMinutes(eval(this.getMinutes() + operator + 1)); 
 
     } else { 
 
     this.setMeridiem(); 
 
     } 
 
     console.log('changed ' + $(input.target).attr('name')); 
 
     this.setText(input); 
 
    }, 
 

 

 
    //Set the input field's time 
 
    setText: function(input) { 
 
     console.log('set ' + $(input.target).attr('name') + ' to ' + this.selectedHour + ' : ' + this.selectedMin + ' ' + this.selectedMeridiem); 
 
     $(input.target).val(this.selectedHour + ' : ' + this.selectedMin + ' ' + this.selectedMeridiem); 
 
    }, 
 

 
    //Get the input field's time 
 
    getText: function(input) { 
 
     return $(input.target).val(); 
 
    } 
 

 

 
    }); 
 

 
    //Create timepickers 
 
    $.fn.timepicker = function(options) { 
 
    return this.each(function() { 
 
     new Timepicker(this, options); 
 
    }); 
 
    }; 
 

 
}(jQuery));
<!DOCTYPE html> 
 
<html> 
 

 
<head lang="en"> 
 
    <meta charset="UTF-8"> 
 
    <title></title> 
 
</head> 
 

 
<body> 
 
    <input type="text" name="event-start-time" id="event-start-time" class="form-input timepicker grid-5" /> 
 
    <input type="text" name="event-end-time" id="event-end-time" class="form-input timepicker grid-5" /> 
 
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script> 
 
    <script> 
 
    $('.timepicker').timepicker({}); 
 
    </script> 
 
</body> 
 

 
</html>

+0

如果将其更改为'$('。timepicker')。是否仍然执行此操作?timepicker();'?你正在传递一个空数组而不是一个对象。不知道它是否重要,但它是奇怪的。 – Leeish

+0

对不起,在我的实际代码中它有一个空对象。它只是未来选项的可能列表。换句话说,是的,它仍然是。 –

+0

“*'//每页仅创建一个时间选择器*”不完全像允许多个实例。你所有的'Timepicker'实例都引用同一个DOM元素。这是预期的吗? – Bergi

回答

0

我能够通过删除以前的向上和向下事件单击事件处理程序,然后重新申请新的单击事件处理程序来解决这个问题。这是通过改变

$(this.up).on('click', $.proxy(this.changeValue, this, '+', element)); 
$(this.down).on('click', $.proxy(this.changeValue, this, '-', element)); 

完成,以

$(this.up).off('click').on('click', $.proxy(this.changeValue, this, '+', element)); 

$(this.down).off('click').on('click', $.proxy(this.changeValue, this, '-', element)); 

感谢所有的建议!