RWD - 自製 jQuery RWD螢幕大小切換事件

在之前一篇 RWD - 簡單RWD概念的Table 中,限量僅僅使用CSS就達成了RWD的切換,前提是目標的DOM結構沒有變化,才透過改變CSS來調整各元素彼此之間的位置關係。但如果遇到了切換前後差異很大的情況下,需要大幅改變DOM的結構調整元素之間的位置,那就需要使用Javascript來操作元素。使用CSS切換只需要定義media就可以自動偵測是否達到切換條件,可是在Javascript中,我們就要自己去偵測視窗大小來判斷是否要切換,因為每次都判斷實在是太麻煩了,所以限量就決定使用自定義jQuery事件來自動觸發切換。


限量使用jQuery一方面是因為jQuery是一套經過長時間淬鍊的Javascript Framework,而且對DOM的操作容易,最重要的是限量比較熟悉的,廢話不多說馬上來看看如何實作。

首先先來看看完整的程式碼:

擴充程式碼

if(typeof jQuery === 'undefined') {
 console.log('jQuery is required');
}

+(function(window, $) {
 var match = window.matchMedia('screen and (max-width: 451px)');
 var rwdMode = null;
 
 // 進行切換作業
 var transformFunc = function (normalCallback, mobileCallback) {
  if (rwdMode === 'normal') {
   // 切換成一般模式
   normalCallback.call(normalCallback);
  } else if (rwdMode === 'mobile') {
   // 切換成手機模式
   mobileCallback.call(mobileCallback);
  } else {
   throw new Error('Can not resolve rwdMode.');
  }
 };
 
 // 觸發RWD轉換事件
 var reframeRWD = function() {
  rwdMode = match.matches ? 'mobile' : 'normal';

  $('*').each(function (index, el) {
   var events = $._data($(el).get(0), "events");
   if (typeof events !== 'undefined') {
    if (events.hasOwnProperty('rwdTransform')) {
     $(el).trigger('rwdTransform', [transformFunc]);
    }
   }
  });
 };
 
 // 取得目前rwdMode值
 window.rwdMode = function() {
  return rwdMode;
 };
 
 // 偵測視窗大小切換
 $(window).on('resize', function () {
  if (match.matches) {     // 偵測到為手機模式
   // 如果目前框架為一般版且尚未切換
   if (rwdMode == 'normal') {
    rwdMode = 'mobile';
    reframeRWD();
   }
  } else {        // 偵測到為一般模式
   // 如果目前框架為手機板且尚未切換
   if (rwdMode == 'mobile') {
    rwdMode = 'normal';
    reframeRWD();
   }
  }
 });

 // 頁面載完後進行RWD轉換
 $(window).on('load', function () {
  reframeRWD();
 });
 
 // 註冊jQuery客製化事件到DOM
 $.fn.rwdTransform = function(normalFunc, mobileFunc) {
  $(this).on('rwdTransform', function(event, baseFunc) {
   baseFunc(normalFunc, mobileFunc);
  });
 };
 
})(window, jQuery);



解說

這段程式碼主要重點有幾個部分:

  1. 註冊jQuery自製事件
  2. 判斷是否觸發自製事件
  3. 執行自製事件處理程序

註冊jQuery自製事件


就像jQuery原生定義的事件一樣,像是Click, Load, Change, Blur...等,這些事件提供好一個介面,開發人員只要根據介面定義丟入需要的參數數量就OK了,所以我們也要根據我們的需求定義好參數數量。在限量的程式碼中,註冊了rwdTransform Function,這個Function定義了一個同名事件,參數分別為normalFunc與mobileFunc,這兩個參數分別為開發人員自定義切換一般模式與切換手機模式的Function。


判斷是否觸發自製事件


事件最重要的兩個地方就是1. 觸發的時間點; 2. 執行的方法。我們何時要觸發事件呢?從最初的想法就是去看看視窗大小是否達到指定的大小,所以限量就在window的resize事件裡去檢查是否符合指定的大小。這裡有個小地方要注意,因為resize事件是只要視窗大小一有改變就會觸發,儘管只變動了1個pixel,因此這邊的判斷要寫得很好,不然視窗一拉就會重複執行一拖拉庫。在限量的程式碼中只針對"狀態"才進行切換,如果達到切換視窗區間且目前狀態未切換的情況下才執行切換程序。

執行自製事件處理程序


最後在觸發事件後就要來執行事件的處理程序,在程式碼的reframeRWD的Function中,除了改變狀態的值之外,還要去搜尋頁面上的每個元素,對有實作rwdTransform事件的元素觸發該事件。為了讓開發人員不須判斷須執行哪個切換方法,限量定義了transformFunc的Function。transformFunc主要是判斷目前RWD狀態來執行相對應的切換方法,在reframeRWD觸發元素的rwdTransform事件時會將transformFunc當作參數傳入,接著就來到前面註冊jQuery的地方了,在註冊jQuery事件的地方我們將開發人員傳入的normalFunc與mobileFunc再傳入transformFunc中執行。

整體RWD切換的事件流程就大概這樣,另外還有其他小部分:


其他


因為RWD狀態是限量用來判斷是否切換的依據,必須只能由系統存取,所以外部只能有唯讀的權限,因此限量在window定義了一個rwdMode的Function,這樣一來開發人員就可以取得rwdMode值也不怕被修改到。

最後附上一個使用的範例操作RWD轉換的流程:

使用範例
$(function() {
 $('#myTable').rwdTransform(function() {
  console.log('normal transform');
 }, function() {
  console.log('mobile transform');
 });
});


這樣建立好RWD觸發事件後就可以輕輕鬆鬆地專心寫一般頁面與手機頁面切換的Javascript Code,不用再去煩惱什麼時候會去切換。




留言