Javascript基礎(面向初學者) (轉載)

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

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

前言

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

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

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

1. 整體設計

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

大概的設計以下:django

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

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

  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("你好!"); }() ) ;

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

(  
    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();

很遺憾,調不到。

咱們再回顧一下代碼:

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

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

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

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

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

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

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

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

是否是也能夠呢?

若是你以爲每次寫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>

舉一個例子,如今咱們要獲取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');

運行結果

嗯,確實取到了呢。

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

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

效果確實出來了。

但是呢,若是用戶過幾天又來個需求,說我要把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);

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

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

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

成了。

咱們如今返回的,不是一個單純的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();

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

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

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

對應的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相關 ---------------------------------// ajax : function(obj){ var defaults = { type : 'post' , data : {} , success : function(data){ } }; // 建立一個ajax對象 var xhr = new XMLHttpRequest(); //開始和後臺的upload.jsp頁面進行交換 xhr.open("post", basePath+"/upload/file.do", true); //上傳成功進入的毀掉函數 xhr.onreadystatechange = function(){ if(xhr.readyState==4 && xhr.status==200){//狀態4和200表明和服務器端交互成功 //獲取上傳成功的返回數據 var data = xhr.responseText.trim(); var jdata = eval("("+data+")"); jdata["target"]=uploadTo; tz_uploadsuccess($(uploadTo),jdata); } }; //監聽文件上傳的進度 xhr.upload.addEventListener("progress", progressFunction, false); //發送文件上傳的進度 xhr.send(form); } , // ------------------------ 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; }

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

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

前言

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

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

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

1. 整體設計

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

大概的設計以下:

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

  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("你好!"); }() ) ;

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

(  
    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();

很遺憾,調不到。

咱們再回顧一下代碼:

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

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

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

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

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

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

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

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

是否是也能夠呢?

若是你以爲每次寫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>

舉一個例子,如今咱們要獲取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');

運行結果

嗯,確實取到了呢。

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

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

效果確實出來了。

但是呢,若是用戶過幾天又來個需求,說我要把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);

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

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

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

成了。

咱們如今返回的,不是一個單純的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();

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

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

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

對應的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相關 ---------------------------------// ajax : function(obj){ var defaults = { type : 'post' , data : {} , success : function(data){ } }; // 建立一個ajax對象 var xhr = new XMLHttpRequest(); //開始和後臺的upload.jsp頁面進行交換 xhr.open("post", basePath+"/upload/file.do", true); //上傳成功進入的毀掉函數 xhr.onreadystatechange = function(){ if(xhr.readyState==4 && xhr.status==200){//狀態4和200表明和服務器端交互成功 //獲取上傳成功的返回數據 var data = xhr.responseText.trim(); var jdata = eval("("+data+")"); jdata["target"]=uploadTo; tz_uploadsuccess($(uploadTo),jdata); } }; //監聽文件上傳的進度 xhr.upload.addEventListener("progress", progressFunction, false); //發送文件上傳的進度 xhr.send(form); } , // ------------------------ 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; }
相關文章
相關標籤/搜索