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>
如果將其更改爲'$('。timepicker')。是否仍然執行此操作?timepicker();'?你正在傳遞一個空數組而不是一個對象。不知道它是否重要,但它是奇怪的。 – Leeish
對不起,在我的實際代碼中它有一個空對象。它只是未來選項的可能列表。換句話說,是的,它仍然是。 –
「*'//每頁僅創建一個時間選擇器*」不完全像允許多個實例。你所有的'Timepicker'實例都引用同一個DOM元素。這是預期的嗎? – Bergi