前言
做過移動Web開發的同學都知道,移動端日期選擇是很常見的需求。在PC端,我們有很豐富的選擇,比較出名的就有Mobiscroll和jQuery UI Datepicker。個人看來,這些插件存在的兩個顯而易見的問題,第一是過重的依賴,對于jQuery的插件,已經強制依賴了80多k的龐然大物,把很多移動端項目拒之門外;第二是太過強大的功能,很多插件花百分之八十的時間去完善插件百分之二十炫酷的額外功能,導致代碼量變大,配置繁雜。所以一款少依賴、輕量級和使用簡單的移動端日期選擇插件是非常必要的。本文簡單介紹近來寫的一款基于zepto的移動端輕量級日期插件--date_picker。
插件設計原則
只保留最必要的功能
日期選擇插件無非就是可以進行年、月、日選擇,并且提供必要的年月切換動畫特效,至于什么最小時間、最大時間、主題定制,概不在本插件功能范圍。
保留必要的依賴
本插件雖說是基于zepto,實際上還隱性依賴了Github上面一個比較牛的庫fastclick。我們知道,移動端點擊事件處理有兩個常見的問題:(1)移動端click事件有300ms,通常采用touch事件來代替click事件來提高靈敏性;(2)touch事件會存在穿透的問題,一般插件都不用touch事件;基于這兩個問題,fastclick做了兼容,只需要簡單調用它提供的api就能夠愉快得和原本一樣調用click事件,所以這個依賴不能省。至于依賴zepto,實際上是可有可無的,一來博主平時工作都是寫原生js的,不用插件也沒多大的感覺,二來插件受眾面就會小一些。不過鑒于zepto在移動端已然和zepto在PC端一樣如魚得水,就毫不客氣采用了。
既能夠支持模塊化又能本地引用文件使用的
久遠一點的插件基本都是讓你下載一個文件,然后用script去引用,這樣本無可厚非,只不過放著最大的包管理器npm不用,豈不是對不起頁面仔這個稱號。所以本插件支持文件引用也支持CMD方式的模塊引用。
功能介紹
直接上圖:
技術細節
transitionEnd事件
插件的主面板是當前月份的天數詳情,如果點擊上一個月或者下一個月插件需要計算出上一個月或者下一個月的天數信息,然后插入到DOM節點中。在插入到DOM節點之后,就需要采用動畫效果來顯示最新的一月并且褪去老的一個月,采用的方式是CSS2d轉化加過渡。我們需要處理的就是在舊的一個月褪去看不見的時候及時從DOM樹中刪除,不然如果用戶一直點下一個月或者上一個月的話,內存會炸的。為了實現這個移除功能,一個辦法是采用setTimeout事件在特定的時間去刪除節點,經過嘗試,發現由于Javascript定時器不準確的特性和前后一個月切換帶來的邏輯復雜度增加,這種方案很不可行。
于是,本插件采用了第二個方案:transitionEnd事件。直接引用一下MDN的介紹:
The transitionend event is fired when a CSS transition has completed. In the case where a transition is removed before completion, such as if the transition-property is removed, then the event will not fire. The event will also not fire if the animated element becomes display: none before the transition fully completes.
也就是只要你不去隨便亂動元素的CSS屬性,在動畫完成的時候,你就可以執行相應的操作(刪除節點)。
再來看看兼容性:
對于移動Web開發足矣!
最后就是在綁定事件的兼容性問題,不同廠商對于這個事件的定義并不一致,比如IOS里面監聽的是transitionend事件,但是在安卓里面監聽transitionend事件完全沒反應,經過一番Google,發現安卓需要監聽webkitTransitionEnd事件。為了解決綁定事件時候的兼容性問題,就需要檢測瀏覽器到底支持哪種事件。下面貼上Stackoverflow上面一個問答的代碼片段:
function whichTransitionEvent() { var t, el = document.createElement('fakeelement'); transitions = { 'OTransition' :'oTransitionEnd', 'MSTransition' :'msTransitionEnd', 'MozTransition' :'transitionend', 'WebkitTransition' :'webkitTransitionEnd', 'transition' :'transitionEnd' }; for(t in transitions){ if( el.style[t] !== undefined ){ return transitions[t]; } } return false; }
安裝使用
安裝
支持下面兩種方式
git clone之后直接拷貝引用bin文件夾下面的datepicker.min.css和datepicker.min.js 從npm下載安裝:npm install --save date_picker使用
引用樣式datepicker.min.css
引用datepicker.min.js或者引用模塊var DatePicker = require('date_picker');
實例化組件,綁定插件日期選擇完成之后的回調函數
var _date = document.getElementById('date'); var datePicker = new DatePicker({ confirmCbk: function(data) { _date.value = data.year + '-' + data.month + '-' + data.day; } }); _date.onfocus = function(e) { _date.blur(); datePicker.open(); };
插件外置兩個API: open和close,其中特別注意上面demo中_date在獲取焦點之后里面強制去除了焦點,是為了避免安卓下面為input標簽設置readonly屬性并不能禁止原生鍵盤彈出的問題。