插件特點:支持zepto庫 支持時間戳格式 支持年月日時分秒格式html
countdown 由jquery依賴庫改爲zeptonode
zepto的event機制與jquery不一樣,因此更換以後代碼不能正常運行jquery
這裏對event機制作下探討web
事件是用來描述網頁中某一特定有趣時刻的,衆所周知事件一般是在由用戶和瀏覽器進行交互時觸發,其實否則,經過Javascript能夠在任什麼時候間觸發特定的事件,而且這些事件與瀏覽器建立的事件是相同的。這就意味着會有適當的事件冒泡,而且瀏覽器會執行分配的事件處理程序。這種能力在測試web應用程序的時候,是很是有用的,在DOM 3級規範中提供了方法來模擬特定的事件,IE9 chrome FF Opera 和 Safari都支持這樣的方式,在IE8及之前的辦法的IE瀏覽器有他本身的方式來模擬事件chrome
a)Dom 事件模擬
能夠經過document上的createEvent()方法,在任什麼時候候建立事件對象,此方法只接受一個參數,既要建立事件對象的事件字符串,在DOM2 級規範上全部的字符串都是複數形式,在DOM 3級事件上全部的字符串都採用單數形式,全部的字符串以下:
UIEvents:通用的UI 事件,鼠標事件鍵盤事件都是繼承自UI事件,在DOM 3 級上使用的是 UIEvent。
MouseEvents:通用的鼠標事件,在DOM 3 級上使用的是 MouseEvent。
MutationEvents:通用的突變事件,在DOM 3 級上使用的是 MutationEvent。
HTMLEvents:通用的HTML事件,在DOM3級上尚未等效的。
注意,ie9是惟一支持DOM3級鍵盤事件的瀏覽器,但其餘瀏覽器也提供了其餘可用的方法來模擬鍵盤事件。
一旦建立了一個事件對象,就要初始化這個事件的相關信息,每一種類型的事件都有特定的方法來初始化,在建立完事件對象以後,經過dispatchEvent()方法來將事件應用到特定的dom節點上,以便其支持該事件。這個dispatchEvent()事件,支持一個參數,就是你建立的event對象。express
對於HTML事件,直接上代碼。
var event = document.createEvent(「HTMLEvents」);
event.initEvent(「focus」, true, false);
target.dispatchEvent(event);瀏覽器
插件源碼地址:app
; (function(factory) { if (typeof define === 'function' && define.amd) { define(['Zepto'], factory); } else { factory(Zepto); } })(function($) { var PRECISION = 1000; // 0.1 seconds, used to update the DOM var instances = [], matchers = []; // Miliseconds // matchers.push(/^[0-9]*$/.source); matchers.push(/^[0-9]*$/.source); // Month/Day/Year [hours:minutes:seconds // matchers.push(/([0-9]{1,2}\/){2}[0-9]{4}( [0-9]{1,2}(:[0-9]{2}){2})?/.source); matchers.push(/([0-9]{1,2}\/){2}[0-9]{4}( [0-9]{1,2}(:[0-9]{2}){2})?/.source); // Year/Day/Month [hours:minutes:seconds // matchers.push(/[0-9]{4}(\/[0-9]{1,2}){2}( [0-9]{1,2}(:[0-9]{2}){2})?/.source); matchers.push(/[0-9]{4}([\/\-][0-9]{1,2}){2}( [0-9]{1,2}(:[0-9]{2}){2})?/.source); // Cast the matchers to a regular expression object matchers.push(/^[0-9]*$/.source); matchers.push(/([0-9]{1,2}\/){2}[0-9]{4}( [0-9]{1,2}(:[0-9]{2}){2})?/.source); matchers.push(/[0-9]{4}([\/\-][0-9]{1,2}){2}( [0-9]{1,2}(:[0-9]{2}){2})?/.source); matchers = new RegExp(matchers.join("|")); // Parse a Date formatted has String to a native object function parseDateString(dateString) { // Pass through when a native object is sent if (dateString instanceof Date) { return dateString; } // Caste string to date object if (String(dateString).match(matchers)) { // If looks like a milisecond value cast to number before // final casting (Thanks to @msigley) if (String(dateString).match(/^[0-9]*$/)) { dateString = Number(dateString); } if (String(dateString).match(/\-/)) { dateString = String(dateString).replace(/\-/g, "/"); } // return new Date(dateString); return new Date(dateString); } else { throw new Error("Couldn't cast `" + dateString + "` to a date object."); } } var DIRECTIVE_KEY_MAP = { 'Y': 'years', 'm': 'months', 'w': 'weeks', 'd': 'days', 'D': 'totalDays', 'H': 'hours', 'M': 'minutes', 'S': 'seconds' }; // Time string formatter function strftime(offsetObject) { // console.log(offsetObject) return function(format) { // console.log(format) var directives = format.match(/%(-|!)?[A-Z]{1}(:[^;]+;)?/gi); if (directives) { for (var i = 0, len = directives.length; i < len; ++i) { var directive = directives[i] .match(/%(-|!)?([a-zA-Z]{1})(:[^;]+;)?/), regexp = new RegExp(directive[0]), modifier = directive[1] || '', plural = directive[3] || '', value = null; // Get the key directive = directive[2]; // Swap shot-versions directives if (DIRECTIVE_KEY_MAP.hasOwnProperty(directive)) { value = DIRECTIVE_KEY_MAP[directive]; value = Number(offsetObject[value]); } if (value !== null) { // Pluralize if (modifier === '!') { value = pluralize(plural, value); } // Add zero-padding if (modifier === '') { if (value < 10) { value = '0' + value.toString(); } } // Replace the directive format = format.replace(regexp, value.toString()); } } } format = format.replace(/%%/, '%'); return format; }; } // Pluralize function pluralize(format, count) { var plural = 's', singular = ''; if (format) { format = format.replace(/(:|;|\s)/gi, '').split(/\,/); if (format.length === 1) { plural = format[0]; } else { singular = format[0]; plural = format[1]; } } if (Math.abs(count) === 1) { return singular; } else { return plural; } } function fireEvent(el, type, extra) { var ev = document.createEvent("HTMLEvents"); // console.log(type); ev.initEvent(type, true, true) for (var key in extra) { ev[key] = extra[key] console.log(extra[key]) } el.dispatchEvent(ev); // console.log(el); } $.fn.On = function(name, cb) { if ($ == Zepto) { this.get(0).addEventListener(name, cb); } else { this.$el.on(name, callback); } } // The Final Countdown var Countdown = function(el, finalDate, callback) { this.el = el; this.$el = $(el); this.interval = null; this.offset = {}; // Set the final date this.setFinalDate(finalDate); // Register this instance this.instanceNumber = instances.length; instances.push(this); // Save the reference this.$el.data('countdown-instance', this.instanceNumber); // Register the callbacks when supplied if (callback) { this.$el.On('update.countdown', callback); this.$el.On('stoped.countdown', callback); this.$el.On('finish.countdown', callback); } this.start(); }; Countdown.prototype.start = function() { if (this.interval !== null) { throw new Error("Countdown is already running!"); } var self = this; this.update(); this.interval = setInterval(function() { self.update.call(self); }, PRECISION); }; Countdown.prototype.stop = function() { clearInterval(this.interval); this.interval = null; this.dispatchEvent('stoped'); }; Countdown.prototype.pause = function() { this.stop.call(this); }; Countdown.prototype.resume = function() { this.start.call(this); }; Countdown.prototype.remove = function() { this.stop(); delete instances[this.instanceNumber]; }; Countdown.prototype.setFinalDate = function(value) { this.finalDate = parseDateString(value); // Cast the given date }; Countdown.prototype.update = function() { // Stop if dom is not in the html (Thanks to @dleavitt) if (this.$el.closest('html').length === 0) { this.remove(); return; } // Calculate the remaining time this.totalSecsLeft = this.finalDate.valueOf() - new Date().valueOf(); // In miliseconds this.totalSecsLeft = Math.ceil(this.totalSecsLeft / 1000); this.totalSecsLeft = this.totalSecsLeft < 0 ? 0 : this.totalSecsLeft; // Calculate the offsets this.offset = { seconds: this.totalSecsLeft % 60, minutes: Math.floor(this.totalSecsLeft / 60) % 60, hours: Math.floor(this.totalSecsLeft / 60 / 60) % 24, days: Math.floor(this.totalSecsLeft / 60 / 60 / 24) % 7, totalDays: Math.floor(this.totalSecsLeft / 60 / 60 / 24), weeks: Math.floor(this.totalSecsLeft / 60 / 60 / 24 / 7), months: Math.floor(this.totalSecsLeft / 60 / 60 / 24 / 30), years: Math.floor(this.totalSecsLeft / 60 / 60 / 24 / 365) }; // Dispatch an event if (this.totalSecsLeft === 0) { this.stop(); this.dispatchEvent('finish'); } else { this.dispatchEvent('update'); } }; Countdown.prototype.dispatchEvent = function(eventName) { var event = {}; //$.Event(eventName + '.countdown'); event.finalDate = this.finalDate; event.offset = $.extend({}, this.offset); event.strftime = strftime(this.offset); if ($ == Zepto) { // console.log(eventName) fireEvent(this.$el.get(0), eventName + '.countdown', event); } else { this.$el.trigger(event); } // console.log(this) // console.log(event); }; // Register the jQuery selector actions $.fn.countdown = function() { var argumentsArray = Array.prototype.slice.call(arguments, 0); // console.log(argumentsArray[1]) return this.each(function() { var instanceNumber = $(this).data('countdown-instance'); // console.log(instanceNumber+'agd') // Verify if we already have a countdown for this node ... if (instanceNumber) { var instance = instances[instanceNumber], method = argumentsArray[0]; // If method exists in the prototype execute if (Countdown.prototype.hasOwnProperty(method)) { instance[method].apply(instance, argumentsArray.slice(1)); // If method look like a date try to set a new final date } else if (String(method).match(/^[$A-Z_][0-9A-Z_$]*$/i) === null) { instance.setFinalDate.call(instance, method); } else { $.error('Method %s does not exist on jQuery.countdown'.replace(/\%s/gi, method)); } } else { // ... if not we create an instance new Countdown(this, argumentsArray[0], argumentsArray[1]); } }); }; });
參考文檔 http://www.cnblogs.com/MrBackKom/archive/2012/06/26/2564501.htmldom