JavaScript : 零基礎打造本身的類庫

寫做不易,轉載請註明出處,謝謝。javascript

文章類別:Javascript基礎(面向初學者)css

前言

在以前的章節中,咱們已經不依賴jQuery,單純地用JavaScript封裝了不少方法,這個時候,你必定會想,這些常用的方法能不能單獨整理成一個js文件呢?html

固然能夠,封裝原本就是幹這個用的。放在一個單獨js文件裏當然不錯,其實咱們也能夠單獨整一個js類庫,一方面能夠鍛鍊一下本身封裝方法的能力,另外一方面,也能夠將本身學到的東西作一個整理。java

出於這個目的,本文將介紹如何封裝一個簡單的js類庫。(固然,只是開一個頭,熟悉一下js基礎而已。實際使用的話我感受徹底沒有必要,由於jQuery已經很強大了,直接使用第三方的就能夠)node

1. 整體設計

所謂的js庫,其實也就是一個js文件,我思前想後,決定取個名字叫「miniQuery」,是否是山寨的味道十足呢?哈,請不要在乎這些小細節。ajax

大概的設計以下:json

  1. 擴展方法的兼容(主要寫一些兼容的擴展方法,好比 forEach 方法等)api

  2. 工具包定義 (就是以前封裝的utils.js,咱們的miniQuery須要依賴這個工具包,爲了方便,就乾脆寫在一個文件裏面了。)數組

  3. miniQuery定義安全

2. 擴展方法的兼容

// ------------------------ 基本擴展, 字符串,數組等---------------------------------//
function extend_base (){
    
    if(!String.prototype.format ){
        String.prototype.format = function() {
            var e = arguments;
            return this.replace(/{(\d+)}/g,function(t, n) {
                return typeof e[n] != "undefined" ? e[n] : t
            })
        };
    }
    
    if (!Array.prototype.forEach && typeof Array.prototype.forEach !== "function") {
        Array.prototype.forEach = function(callback, context) {
           // 遍歷數組,在每一項上調用回調函數,這裏使用原生方法驗證數組。
           if (Object.prototype.toString.call(this) === "[object Array]") {
               var i,len;
               //遍歷該數組全部的元素
               for (i = 0, len = this.length; i < len; i++) {
                   if (typeof callback === "function"  && Object.prototype.hasOwnProperty.call(this, i)) {
                       if (callback.call(context, this[i], i, this) === false) {
                           break; // or return;
                       }
                   }
               }
           }
        };
    }
    
    if(!String.prototype.format ){
        Array.isArray = function(obj){
            return obj.constructor.toString().indexOf('Array') != -1;
        }
    }


    //待補充 ...
    
}

咱們定義一個extend_base方法,裏面主要對js內置對象的api作了一些兼容性補充,目前還不完善,只有寥寥幾個方法。固然,若是你不考慮IE678的話,那麼基本上不須要這一部分了。

定義完成後當即調用。

extend_base();

2. 工具包整合

// ------------------------ 工具包---------------------------------//
var utils = {
            center : function(dom){
                dom.style.position = 'absolute';
                dom.style.top = '50%';
                dom.style.left = '50%';
                dom.style['margin-top'] = - dom.offsetHeight / 2 + 'px';
                dom.style['margin-left'] = - dom.offsetWidth / 2 + 'px';
            },
        
            /** dom相關 * */
            isDom : ( typeof HTMLElement === 'object' ) ?
                function(obj){
                    return obj instanceof HTMLElement;
                } :
                function(obj){
                    return obj && typeof obj === 'object' && obj.nodeType === 1 && typeof obj.nodeName === 'string';
                } ,
             
            /** 數組相關 * */
            isArray : function(obj){
                return obj.constructor.toString().indexOf('Array') != -1;
            }
            
        }
  • center :控制dom元素相對於父盒子居中
  • isDom :判斷是否爲dom元素
  • isArray :判斷是否爲數組

3. miniQuery整體設計

終於到miniQuery了,在寫代碼以前,先簡單說一下自執行函數。

可能你在不少書上,或者下載的源碼裏面,常常會看到這樣的代碼:

(function(){
    
})();

這樣子你或許以爲很奇怪,沒事,咱們一塊兒來分析。

在js中,你若是把函數看做一個數據類型,和其餘語言中的 Integer, Float , String等等同樣,就會理解不少事情了。固然,其實在js中,函數自己就是一個對象,否則的話就不會出現call方法了。由於只有對象才能夠調用方法嘛。不過,大部分狀況下,你把函數理解爲數據類型就能夠了。

匿名函數:

function(){
    
}

這是一個函數,由於沒有函數名,因此是一個匿名函數。你定義了它,若是接下來你不想經過函數調用的方式來執行它,那麼是否是能夠直接給它打一個括號來執行呢?

像這樣:

function(){
    
}();

不過,由於js語法的關係,這樣子是不能執行的,你須要用一對圓括號來包一下:

(  
    function(){
    alert("你好!");
    }()  
) ;

Paste_Image.png

這樣就能夠了,下面是另外一種寫法:

(  
    function(){
    alert("你好!");
    }  
)();

這樣也能夠,這種寫法會更多一點。它的意思就是說,我不關心你這個函數叫什麼名字,反正你在被定義的時候就要給我執行,這就是所謂的自執行函數。

好,問題來了,怎麼加參數呢?

之前咱們習慣於這麼寫:

function say(str){
    alert(str);
 } 

say("你好!");

依葫蘆畫瓢

(  
    function(str){
       alert(str);
    }  
)("你好!");

OK了。

是否是同樣的意思呢?

沒啥區別,之前怎麼作,如今還怎麼作,無非就是一個函數傳參的事情罷了。

咱們將圓括號的位置調整一下

( function(str){
    alert(str);
} )("你好!");

這樣差很少就是最終的版本了,我記得初學js的時候,看這種代碼很吃力,好像在看外星語言同樣,後來看多了也就習慣了。

自執行函數就是這麼一回事,沒什麼大不了的。

有了上面的解釋,之後若是你再遇到這種寫法,就 so easy 啦。

因此,不要再恐懼了,它就是這麼回事,沒什麼大不了的,我這麼後知後覺的人都能寫,你也能夠。我花了半年的時間纔看明白,我相信你如今只須要幾分鐘。個人意思是,若是你以前不知道這些的話。

那麼,何時用自執行函數呢?

當你以爲某個函數只須要執行一次,並且不須要在其餘地方調用的時候,就用。

你可能會問了,我幹嗎要這樣寫啊,反正就執行一次,我直接把實現代碼寫在外面不就好了?

緣由很簡單,由於那樣的話,你定義的變量就會是全局的,而通常來講咱們設計的原則是儘可能不要使用全局變量。

而採用這種方式,咱們就造成了一個匿名函數,函數的定義又會造成閉包,因此比較安全和簡潔。

你可能還會以爲疑惑,我幹嗎要這些寫,若是我非要給函數取一個名字,而後立刻調用呢?

額,其實我我的認爲這也是沒有問題的,可是你得費一番心思去給函數取名字,取 a,b,c,d 這樣的名字確定是很差的。那麼,我私覺得,還不如干脆就用匿名函數算了,免得麻煩。

若是這部分知識你之前就不知道,那麼我建議你把這篇文章多看幾遍,反正就是那麼回事,沒什麼大不了的。我當初就是走了不少彎路,也沒有人教我,只有靠本身在那瞎摸索和各類百度,固然,如今想一想很簡單了。

咱們的miniQuery的定義就放在這個自執行函數裏面,這樣一來,只要有人調用了這個js文件,就能調用miniQuery函數了。

固然,你直接放在外面其實也沒事,由於反正就一個方法,並且這個方法原本就是要暴露出去的。

這邊爲了說明自執行函數,就硬加進來了。

咱們把miniQuery的定義丟進去。

好比,像這樣子的:

(function(){
   
   var miniQuery = function(){
    alert('Hello miniQuery!');
   }
   
})();

咱們嘗試在外面調用:

miniQuery();

很遺憾,調不到。

Paste_Image.png

咱們再回顧一下代碼:

(function(){
   
   var miniQuery = function(){
        alert('Hello miniQuery!');
   }
   
})();

miniQuery();

原來,miniQuery是存在於一個閉包中的,它能夠訪問到父級做用域的變量,可是反過來就不行,除非函數本身用 return 的方式將私有數據暴露出去。這些在以前的關於閉包的文章裏面已經解釋過了,這裏再也不贅述。

解決方法有不少,好比,最簡單的,咱們直接把var去掉,這樣就會發生一次變量提高,miniQuery被升級爲全局變量,掛在window對象上面。

(function(){
   
   miniQuery = function(){
    alert('Hello miniQuery!');
   }
   
})();

miniQuery();

Paste_Image.png

成了,簡單明瞭,乾乾淨淨。

雖然我以爲頗有道理,可是我看別人的代碼,他們封裝本身的js庫的時候,幾乎沒有這樣作的,所以咱們也採用一種大衆的作法。

即,咱們把window做爲參數傳進去,而後手動將miniQuery掛上去。

(function(win){
   
   var miniQuery = function(){
    alert('Hello miniQuery!');
   }

   win.miniQuery = miniQuery;
   
})(window);

miniQuery();

Paste_Image.png

是否是也能夠呢?

若是你以爲每次寫miniQuery太麻煩,那麼咱們能夠給它換一個名字,好比 $

(function(win){
   
   var miniQuery = function(){
    alert('Hello miniQuery!');
   }
   
   
   win.$ = miniQuery;
   
})(window);

$();

這樣就差很少了。

4. miniQuery 包裹對象

咱們先弄來一個測試用的網頁:

.wrap {
    width:80px;
    height:80px;
    background:darkslateblue;
    margin:20px;
    border-radius: 2px;
}
<body>
    <div class='boxes'>
        <div id='box1' class='wrap'></div>
        <div id='box2' class='wrap'></div>
        <div id='box3' class='wrap'></div>
    </div>
</body>

Paste_Image.png

舉一個例子,如今咱們要獲取id爲box1的盒子,並把它的背景色改成紅色。

用js代碼,咱們會這樣作:

var box2 = document.getElementById('box2');
box2.style.backgroundColor = 'red';

思路很清晰,分爲簡單的兩步:

第一步:獲取dom對象。
第二部:設置其背景色爲紅色。

一樣的,咱們的 miniQuery 也要這麼作,首先得獲取對象,而後進行操做。就好像你作飯,首先得有米麪吧。所謂巧婦難爲,無米之炊。

因而,咱們有了下面的代碼:

var miniQuery = function(selector){
   var miniQuery = document.getElementById(selector);
   console.log(miniQuery);
}

selector 表明選擇器,它只是一個參數名字,參數列表的名稱是能夠本身定義的。你寫 aaa , bbb , ccc 都沒問題,只要你願意的話。

我之前常常看別人寫的代碼,參數裏面有callback,如今我知道是回調函數的意思。但是我之前不知道,而後就以爲很困惑,做爲一個英語比日語還差的js玩家,我感到很那個啥。

其實無所謂,只是一個名字而已,你寫什麼都行,只要符合標識符的命名規範就成。

總有人以爲,看到參數裏邊寫了context(上下文),callback(回調函數)這樣的詞彙,就以爲很困惑。

不要困惑啦,不要再驚恐啦,它就是一個名稱罷了!

。。。

額,扯遠了,繼續回來。

咱們在外面調用miniQuery ~

window 上面掛的是 $ , 其實就是 miniQuery

$('box1');

運行結果

Paste_Image.png

嗯,確實取到了呢。

接下里,咱們給dom元素變動背景色爲紅色。

var miniQuery = function(selector){
   var miniQuery = document.getElementById(selector);
   miniQuery.style.backgroundColor = 'red';
}

Paste_Image.png

效果確實出來了。

但是呢,若是用戶過幾天又來個需求,說我要把box1的寬度變爲以前的兩倍,你怎麼辦?

總不可能去修改源碼吧!

這時候,咱們就能夠考慮能不能經過一個什麼辦法,我先用miniQuery把你傳進來的東西包裝成dom元素,保存起來返回給你,同時再給你返回一大堆方法,好比改變高度啊,添加背景色啊等等。那麼,操做的就是以前保存的元素了。也就是你一開始但願操做的元素。

這是一個很好的想法,咱們通過代碼的重寫,最終產生了這樣的一個miniQuery函數:

var miniQuery = function(selector){
    var miniQuery = document.getElementById(selector);
    
    return {
        obj : miniQuery , //將dom元素保存起來,再返回給你
        
        // ------------------------ css 相關 ------------------------//
        backgroundColor : function(color){
            this.obj.style.backgroundColor = color;
        }
    }
}
   
   win.$ = miniQuery;
   
})(window);

咱們再調用一次,看看這回它給咱們返回的是什麼東東?

var $box = $('box1');
console.log($box);

Paste_Image.png

可見,它給咱們返回的是一個json對象,裏面有 obj 變量和 backgroundColor 函數。這樣的好處就是極大的擴展了咱們的miniQuery,你給我一個選擇器,我就包起來,而後不只把它返回給你,並且還給你各類api方法!

因而咱們就能夠直接調用 backgroundColor 函數了。

var $box = $('box1');
$box.backgroundColor('red');

Paste_Image.png

成了。

咱們如今返回的,不是一個單純的dom元素,dom元素只是它的一部分。能夠說,咱們返回給用戶的是一個miniQuery對象!

通過改進,我已經陸陸續續地給miniQuery添加了不少方法,大部分是模擬的jQuery:

順便弄了兩個小型的組件,一個是按鈕,另外一個是簡單的數據列表。

按鈕使用:

<link rel="stylesheet" type="text/css" href="css/mui.css"/>
<div class='box'></div>
var $box = $('.box').eq(0);
$box.linkbutton();

Paste_Image.png

按鈕的樣式就出來了,而後咱們來設置按鈕的屬性。

var $box = $('.box').eq(0);
$box.linkbutton({
    text : '保存' ,
    click : function(){
        alert('保存成功!');
    }
});

Paste_Image.png

按鈕的大小也自動變大了。

123.gif

對應的css:

mui.css

.linkbutton {
    padding: .4em .9em; /*em的好處就是隨着父元素的字體大小而變化,當該元素的字體變化時,會自適應*/
    border: 1px solid rgba(0,0,0,.1);
    background-color: #ac0;
    border-radius: .2em;
    box-shadow: 0 1px 5px rgba(0,0,0,.5);
    color: #fff;
    text-shadow: 0 -.06em .24em rgba(0,0,0,.5); /*將陰影設置爲半透明,就無所謂底色了,都能很好地適應*/
    font-size: 130%; 
    line-height: 1.5; /*行高是字號的1.5倍*/
    display:inline-block;
    cursor:pointer;
    font-family: "微軟雅黑";
}

數據列表簡單演示:

<!DOCTYPE html>
<html>
    <head>
        <meta charset="UTF-8">
        <link rel="stylesheet" type="text/css" href="css/mui.css"/>
        <script type="text/javascript" src="js/miniQuery.js"></script>
    </head>
    <body>
        <a id='btn0'></a>
        
        <div id='grid0'></div>
    </body>
    <script>
        $('#btn0').linkbutton({
            text : '測試' ,
            click : function(){
                if(grid0.getSize() < 1){
                    alert('請選擇一條數據!');
                    return;
                }
                alert('您選擇的是' + JSON.stringify(grid0.getSelected()));
            }
        });
        var grid0 = mui.get('#grid0').dataGrid({
            header : [
                {name:'ID' ,  width:10 , type : 'checkColumn' } ,
                {name:'標題' , type : 'column' , field : 'title'} ,
                {name:'分類' , type : 'column' , field : 'type'} ,
                {name:'做者' ,  type : 'column' , field : 'author'} ,
                {name:'時間' ,  type : 'column' , field : 'time'} ,
            ] ,
            
        });
        
        
        grid0.load([
            {title : '111' , type : 'A' , author : '張三' , time : '2015'} ,
            {title : '222' , type : 'B' , author : '李四' , time : '2015'} ,
            {title : '333' , type : 'C' , author : '王五' , time : '2015'} ,
            {title : '444' , type : 'D' , author : '趙六' , time : '2015'} ,
        ]);
        
        
        
    </script>
</html>

固然,好多組件都還不夠完善,我主要也是本身嘗試一下,不過並不打算再拓展了。

本身作個小類庫主要用於學習,之後仍是用jQuery吧。

附錄A


"use strict";

/**
 * miniQuery 和 工具類庫
 * 版本 1.1 (修正了一部分Bug,增長了一些方法)
 * 做者:剽悍一小兔
 */

// ------------------------ 基本擴展, 字符串,數組等---------------------------------//
function extend_base (){
    
    if(!String.prototype.format ){
        String.prototype.format = function() {
            var e = arguments;
            return this.replace(/{(\d+)}/g,function(t, n) {
                return typeof e[n] != "undefined" ? e[n] : t
            })
        };
    }
    
    if (!Array.prototype.forEach && typeof Array.prototype.forEach !== "function") {
        Array.prototype.forEach = function(callback, context) {
           // 遍歷數組,在每一項上調用回調函數,這裏使用原生方法驗證數組。
           if (Object.prototype.toString.call(this) === "[object Array]") {
               var i,len;
               //遍歷該數組全部的元素
               for (i = 0, len = this.length; i < len; i++) {
                   if (typeof callback === "function"  && Object.prototype.hasOwnProperty.call(this, i)) {
                       if (callback.call(context, this[i], i, this) === false) {
                           break; // or return;
                       }
                   }
               }
           }
        };
    }
    
    if(!String.prototype.format ){
        Array.isArray = function(obj){
            return obj.constructor.toString().indexOf('Array') != -1;
        }
    }
    
}


extend_base(); 


// ------------------------ 工具包---------------------------------//
var utils = {
            center : function(dom){
                dom.style.position = 'absolute';
                dom.style.top = '50%';
                dom.style.left = '50%';
                dom.style['margin-top'] = - dom.offsetHeight / 2 + 'px';
                dom.style['margin-left'] = - dom.offsetWidth / 2 + 'px';
            },
        
            /** dom相關 * */
            isDom : ( typeof HTMLElement === 'object' ) ?
                function(obj){
                    return obj instanceof HTMLElement;
                } :
                function(obj){
                    return obj && typeof obj === 'object' && obj.nodeType === 1 && typeof obj.nodeName === 'string';
                } ,
             
            /** 數組相關 * */
            isArray : function(obj){
                return obj.constructor.toString().indexOf('Array') != -1;
            }
            
        }
        


// ------------------------ miniQuery.js ---------------------------------//
;(function(win){
    
    var miniQuery = function(selector){
        var miniQuery = null;
        var length = 0;
        var children = [];
        if(!selector) return;
        
        /** 1. 傳入的是id * */
        if(selector.toString().indexOf('#') != -1) {
            selector = selector.replace('#','');
            miniQuery = document.getElementById(selector);
        } 
        
        /** 2. 傳入的是class * */
        else if(selector.toString().indexOf('.') != -1){
            selector = selector.replace('.','');
            miniQuery = document.getElementsByClassName(selector);
        }
        
        
        /** 3. 傳入的是dom元素 * */
        else if(utils.isDom(selector)){
            miniQuery = selector;
        }
        
         /** 4. 傳入的是標籤 * */
        else if(typeof selector === 'string'){
            miniQuery = document.getElementsByTagName(selector);
            return miniQuery;
        }
        
        if(!miniQuery) return; //若是本類庫包裝不了,就返回
        
        if(miniQuery.length){   //若是是一個類數組元素的話,就獲取他的長度
            length = miniQuery.length; 
        }else{
            length = 1; //這種狀況,說明成功包裹了元素,可是該元素仍是存在的,就將長度設定爲1
        }
        
        children = miniQuery.children; //取得全部的孩子節點
        
        return {
            
            /** 屬性區 */
            obj : miniQuery,    //返回的dom元素
            index : 0 ,         //默認的角標(假如 miniquery 是一個類數組的話)
            length : length,    //元素的個數(假如 miniquery 是一個類數組的話)
            children : children,//全部孩子節點
            
            
            /** 方法區 */
            
            // ------------------------ dom 相關 ---------------------------------//
            
            /**獲取dom對象自己,返回純粹的dom元素,而非miniQuery元素*/
            getObj : function(){
                return this.obj;
            } ,
            
            /**獲取元素的長度*/
            size : function(){
                return this.length;
            } ,
            
            /** 假如 miniquery 是一個類數組的話,用於返回其中一個元素 */
            eq : function(index){
                if(length > 0) {
                    return $(this.obj[index]); //eq返回的仍是miniQuery對象
                }else{
                    return null;
                }
            } ,
            
            /** 得到第一個匹配元素 */
            first : function(){
                return $(this.obj[0]);
            } ,
            
            /** 得到最後一個匹配元素 */
            last : function(){
                return $(this.obj[this.length - 1]);
            } ,
            
            /** 得到最後一個匹配元素 */
            getChildren : function(){
                return this.obj.children;
            } ,
            
            /** 得到某一個孩子節點 */
            getChild : function(i){
                return $(this.children[i]);
            } ,
            
            /** 得到父節點 */
            getParent : function(){
                return $(this.obj.parentElement);
            } ,
            
            /** 得到上一個節點 */
            previous : function(){
                var parent = this.getParent();
                var children = parent.children;
                for(var i = 0; i < children.length; i++){
                    if(this.obj == children[i]) {
                        return $(children[i - 1]);
                    }
                }
                return null;
            } ,
            
            /** 得到下一個節點 */
            next : function(){
                var parent = this.getParent();
                var children = parent.children;
                for(var i = 0; i < children.length; i++){
                    if(this.obj == children[i]) {
                        return $(children[i + 1]);
                    }
                }
                return null;
            } ,
            
            findClassDom : function(className){
                 this.obj = this.obj.getElementsByClassName(className) ;
                 return this ;
            } ,
            
            findIdDom : function(id){
                 var $this = this; 
                 var children = this.getChildren();
                 children = Array.prototype.slice.call(children); //obj 轉  []
                 children.forEach(function(item){
                    //console.log(item.id);
                    (id === item.id) && ($this = item) ;
                 });
                 return this ;
            } ,
            
            // ------------------------ css 相關 ---------------------------------//
            /** 添加背景色 */
            backgroundColor : function(color){
                this.obj.style.backgroundColor = color;
                return this;
            } ,
            
            /** 獲取style */
            getStyle : function(){
                var styleEle = null;
                if(window.getComputedStyle){
                    styleEle = window.getComputedStyle(this.obj,null);
                }else{
                    styleEle = ht.currentStyle;
                }
                return styleEle;
             } ,
            
            /** 設置或者拿到高度 */ 
            height : function(h){
                if(!h) return this.getStyle().getPropertyValue('height');
                (typeof h == 'number') && (h = h + 'px');
                this.obj.style.height = h;
                return this;
            } ,
            
            /** 設置或者拿到寬度 */ 
            width : function(w){
                if(!w) return this.getStyle().getPropertyValue('width');
                (typeof w == 'number') && (w = w + 'px');
                this.obj.style.width = w;
                return this;
            } ,
            
            /** 設置自定義樣式 */
            css : function(obj){
                if(!obj) return;
                for(var key in obj){
                    //console.log(key + '=========' + obj[key]);
                    this.obj.style[key] = typeof obj[key] === 'number' ? obj[key] + 'px' : obj[key];
                }
                return this;
            } ,
            
            /** 設置放大 倍數*/
            scale : function(scaleNumber){
                this.css({
                    scale : scaleNumber
                });
                return this;
            } ,
            
            
            hasClass : function(cls) {  
                return this.obj.className.match(new RegExp('(\\s|^)' + cls + '(\\s|$)'));  
            }  ,
            
            addClass : function(cls){
                if (!this.hasClass(cls)) this.obj.className += " " + cls;  
            } ,
            
            removeClass : function(cls) {  
                if (this.hasClass(cls)) {  
                    //console.log(this.obj);
                    var reg = new RegExp('(\\s|^)' + cls + '(\\s|$)');  
                    this.obj.className = this.obj.className.replace(reg, ' ');  //修正bug,以前右邊少了一個this
                }  
            } ,
            
            toggleClass : function(cls){  
                if(this.hasClass(cls)){  
                    this.removeClass(cls);  
                }else{  
                    this.addClass(cls);  
                }  
            }  ,
            
            
            
            // ------------------------ 動畫 相關 ---------------------------------//
            
            //TODO
            animate : function(){
                
            } ,
            
            // ------------------------ 事件相關 ---------------------------------//
            
            on : function(eventName,callback){
                var $this = this;
                this.obj['on' + eventName] = function(){
                    callback.call($this,$this.obj); //context指向$this,參數傳入dom對象
                };
                return this;
            } ,
            
            // ------------------------ 屬性相關 ---------------------------------//
            
            attr : function(attr){
                return this.obj.attributes[attr];
            } ,
            
            
            // ------------------------ ajax相關 ---------------------------------//
            
            
            
            // ------------------------ ui ---------------------------------//
            
            /** 按鈕 * */
            linkbutton : function(opts){
                var opts = opts || {};
                /**添加基本樣式* */
                this.addClass('linkbutton');
                this.on('mouseover' , function(e){
                    //console.log(e);
                    this.css({
                        backgroundColor: '#d4ef50'
                    });
                }).on('mouseout',function(e){
                    this.css({
                        backgroundColor: '#ac0'
                    });
                });
                
                opts.text && (this.obj.innerText = opts.text);
                opts.click && (this.on('click' , opts.click));
            } ,
            
            /** 數據列表 * */
            dataGrid : function(opts){
                var $this = this;
                var opts = opts || {};
                var header = null; //表頭
                var id = null; //grid的id,惟一
                var tb_id = null;
                var tbody_id = null;
                var count = 0; //爲了防止id重複
                var columns = []; //存放field
                var types = [];
                if(!this.obj.id) return;
                else id = this.obj.id;
                
                if(!opts.header) return;
                else header = opts.header;
                
                /**添加基本樣式* */
                this.addClass('tableBox');
                
                //初始化表頭
                function initHeader(){
                    var time = new Date().getTime();
                    tb_id = 'mui-table_' + time + '_' + count++;
                    var html = " <table id='"+tb_id+"'><thead>" ;
                    
                    //拼接表頭
                    html += '<tr>' ;
                    header.forEach(function(item){
                        columns.push(item.field); //添加字段名
                        types.push(item.type);    //添加列類型
                        var width = null;
                        if(item.width) width = item.width + 'px'; //設置寬度
                        if(width) width = "width='"+width+"' ";
                        html += "<th "+width+">" + item.name + '</th>'
                    });
                    tbody_id = 'mui-table-tbody_' + time + '_' + count++;
                    html += "</tr></thread><tbody id='"+tbody_id+"'></tbody>" ;
                    html += '</table>' ;
                    
                    $this.obj.innerHTML = html;
                }
                
                
                //
                initHeader();
                
                return {
                    tbody_id : tbody_id ,
                    allData : null ,
                    ids : [], //保存每一行的id
                    index : 0,//做爲行號和id
                    //加載數據
                    load : function(data){
                        this.allData = data;
                        var html = '';
                        //console.log($('#' + tbody_id));
                        var len = data.length; //總行數
                        var columnSize = columns.length;//總列數
                        //alert(len);
                        for(var i = 0;i < len ; i++){
                            this.ids.push('mui-dataGrid-tr_' + ( new Date().getTime() ) + '_' + this.index++) ;
                            //console.log(this.ids[this.index - 1]);
                            //console.log(this.ids[this.index - 1].substring(this.ids[this.index - 1].length - 1 )); //獲取行號
                            html += "<tr id='"+this.ids[this.index - 1]+"'>"; /*以前在這裏少了一個單引號,最終顯示的數據只有所有的一半,如今已經更正*/
                            //遍歷列
                            //console.log(types);
                            for(var j = 0; j < columnSize ; j++){
                                var columnName = columns[j];
                                if(data[i][columnName]){
                                    html += '<td>' + data[i][columnName] + '</td>';
                                }else if(types[j] == 'checkColumn'){
                                    html += '<td><input type="checkbox" value=""/></td>';
                                }else {
                                    html += '<td></td>';
                                }
                                
                            }
                            //列遍歷完後,這一行才結束
                            html += '</tr>'
                            
                        }
                        
                        //展現數據
                        win.$('#' + this.tbody_id).obj.innerHTML = html;
                        
                        //給每一行添加事件
                        this.ids.forEach(function(rowId){
                            win.$('#' + rowId).on('click',function(){
                                this.toggleClass('selected');
                                if(this.hasClass('selected')){
                                    this.obj.getElementsByTagName('input')[0].checked = true;
                                }else {
                                    this.obj.getElementsByTagName('input')[0].checked = false;
                                }
                            });
                        });
                        
                        
                            
                    } ,
                    
                    //獲取全部數據
                    getData : function(){
                        return this.allData;
                    } ,
                    
                    //根據行號獲取某一行
                    
                    getRow : function(rowIndex){
                        return this.getData()[rowIndex];
                    } ,
                    
                    //獲取全部的行號
                    getSize : function(){
                        var len = 0;
                        this.getSelected && (len = this.getSelected().length) ;
                        return len;
                    } ,
                    
                    //返回選中的行,一條或者多條
                    getSelected : function(){
                        var rows = win.$('.selected').obj; //獲取全部選中行
                        var len = 0;
                        len = rows.length;
                        var arr = [];
                        for(var i = 0;i < len;i++){
                            //console.log(rows[i].id.substring(rows[i].id.length - 1));
                            arr.push(this.getRow(rows[i].id.split('_')[2])) ;
                        }
                        
                        arr.length == 1 && ( arr = arr[0] );
                        
                        return arr;
                        
                        //this.ids[this.index - 1].substring(this.ids[this.index - 1].length - 1 )
                    }
                    
                    
                    
                    
                };

            }
            
        }
    }
    
    win.$ = miniQuery;
    
    win.mui = {
        get : function(sel){
            return miniQuery(sel);
        }
    }
    
})(window);

附錄B mui.css

.linkbutton {
    padding: .4em .9em; /*em的好處就是隨着父元素的字體大小而變化,當該元素的字體變化時,會自適應*/
    border: 1px solid rgba(0,0,0,.1);
    background-color: #ac0;
    border-radius: .2em;
    box-shadow: 0 1px 5px rgba(0,0,0,.5);
    color: #fff;
    text-shadow: 0 -.06em .24em rgba(0,0,0,.5); /*將陰影設置爲半透明,就無所謂底色了,都能很好地適應*/
    font-size: 130%; 
    line-height: 1.5; /*行高是字號的1.5倍*/
    display:inline-block;
    cursor:pointer;
    font-family: "微軟雅黑";
}

.tableBox{
    width:1200px;
    background:#f9f9f9;
    margin:20px auto 0;
    padding:6px;
    position:relative;
    font-family: 微軟雅黑;
}

.tableBox table{
    width:100%;
    border:2px solid #fff;
    
}

.tableBox table tr {
    border-collapse: separate;   
    border-spacing: 1px;
}

/*選中行*/
.tableBox table tr.selected {
    background:#cce4f3;
} 

/*表頭*/
.tableBox  th{  
    background: #eaeaea;
    padding: 6px;
    color: #666;
    font-size: 14px;
}

.tableBox  td {
    font-size: 13px;
    padding: 4px 10px;
}

畢竟是本身DIY出來的,因此沒仔細測試,確定還有一些BUG。不過無論怎麼說,都算是一次嘗試吧,呵呵。

相關文章
相關標籤/搜索