參考資料:MDN: html global attribute或者W3C HTML global-attributesjavascript
web語義化是指經過HTML標記表示頁面包含的信息,包含了HTML標籤的語義化和css命名的語義化。php
HTML標籤的語義化是指:經過使用包含語義的標籤(如h1-h6)恰當地表示文檔結構css
css命名的語義化是指:爲html標籤添加有意義的class,id補充未表達的語義,如Microformat經過添加符合規則的class描述信息html
爲何須要語義化:前端
rfc2616中進行了定義:java
一個請求報文例子以下:node
1 GET /Protocols/rfc2616/rfc2616-sec5.html HTTP/1.1 2 Host: www.w3.org 3 Connection: keep-alive 4 Cache-Control: max-age=0 5 Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8 6 User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/35.0.1916.153 Safari/537.36 7 Referer: https://www.google.com.hk/ 8 Accept-Encoding: gzip,deflate,sdch 9 Accept-Language: zh-CN,zh;q=0.8,en;q=0.6 10 Cookie: authorstyle=yes 11 If-None-Match: "2cc8-3e3073913b100" 12 If-Modified-Since: Wed, 01 Sep 2004 13:24:52 GMT 13 14 name=qiu&age=25
rfc2616中進行了定義:git
響應報文例子以下:github
1 HTTP/1.1 200 OK 2 Date: Tue, 08 Jul 2014 05:28:43 GMT 3 Server: Apache/2 4 Last-Modified: Wed, 01 Sep 2004 13:24:52 GMT 5 ETag: "40d7-3e3073913b100" 6 Accept-Ranges: bytes 7 Content-Length: 16599 8 Cache-Control: max-age=21600 9 Expires: Tue, 08 Jul 2014 11:28:43 GMT 10 P3P: policyref="http://www.w3.org/2001/05/P3P/p3p.xml" 11 Content-Type: text/html; charset=iso-8859-1 12 {"name": "qiu", "age": 25}
雅虎Best Practices for Speeding Up Your Web Site:web
漸進加強是指在web設計時強調可訪問性、語義化HTML標籤、外部樣式表和腳本。保證全部人都能訪問頁面的基本內容和功能同時爲高級瀏覽器和高帶寬用戶提供更好的用戶體驗。核心原則以下:
參考RFC 2616
概念:將多個小圖片拼接到一個圖片中。經過background-position和元素尺寸調節須要顯示的背景圖案。
優勢:
缺點:
聯繫:它們都能讓元素不可見
區別:
原理:利用不一樣瀏覽器對CSS的支持和解析結果不同編寫針對特定瀏覽器樣式。常見的hack有1)屬性hack。2)選擇器hack。3)IE條件註釋
1 <!--[if IE 6]> 2 Special instructions for IE 6 here 3 <![endif]-->
1 /***** Selector Hacks ******/ 2 3 /* IE6 and below */ 4 * html #uno { color: red } 5 6 /* IE7 */ 7 *:first-child+html #dos { color: red } 8 9 /* IE7, FF, Saf, Opera */ 10 html>body #tres { color: red } 11 12 /* IE8, FF, Saf, Opera (Everything but IE 6,7) */ 13 html>/**/body #cuatro { color: red } 14 15 /* Opera 9.27 and below, safari 2 */ 16 html:first-child #cinco { color: red } 17 18 /* Safari 2-3 */ 19 html[xmlns*=""] body:last-child #seis { color: red } 20 21 /* safari 3+, chrome 1+, opera9+, ff 3.5+ */ 22 body:nth-of-type(1) #siete { color: red } 23 24 /* safari 3+, chrome 1+, opera9+, ff 3.5+ */ 25 body:first-of-type #ocho { color: red } 26 27 /* saf3+, chrome1+ */ 28 @media screen and (-webkit-min-device-pixel-ratio:0) { 29 #diez { color: red } 30 } 31 32 /* iPhone / mobile webkit */ 33 @media screen and (max-device-width: 480px) { 34 #veintiseis { color: red } 35 } 36 37 /* Safari 2 - 3.1 */ 38 html[xmlns*=""]:root #trece { color: red } 39 40 /* Safari 2 - 3.1, Opera 9.25 */ 41 *|html[xmlns*=""] #catorce { color: red } 42 43 /* Everything but IE6-8 */ 44 :root *> #quince { color: red } 45 46 /* IE7 */ 47 *+html #dieciocho { color: red } 48 49 /* Firefox only. 1+ */ 50 #veinticuatro, x:-moz-any-link { color: red } 51 52 /* Firefox 3.0+ */ 53 #veinticinco, x:-moz-any-link, x:default { color: red } 54
1 /* IE6 */ 2 #once { _color: blue } 3 4 /* IE6, IE7 */ 5 #doce { *color: blue; /* or #color: blue */ } 6 7 /* Everything but IE6 */ 8 #diecisiete { color/**/: blue } 9 10 /* IE6, IE7, IE8 */ 11 #diecinueve { color: blue\9; } 12 13 /* IE7, IE8 */ 14 #veinte { color/*\**/: blue\9; } 15 16 /* IE6, IE7 -- acts as an !important */ 17 #veintesiete { color: blue !ie; } /* string after ! can be anything */
block元素特色:
inline元素特色
參考資料: 選擇正確的圖片格式
GIF:
JPEG:
PNG:
1 .target { 2 min-height: 100px; 3 height: auto !important; 4 height: 100px; // IE6下內容高度超過會自動擴展高度 5 }
1 <style type="text/css"> 2 .outer { 3 width: 215px; 4 height: 100px; 5 border: 1px solid red; 6 overflow: auto; 7 position: relative; /* 修復bug */ 8 } 9 .inner { 10 width: 100px; 11 height: 200px; 12 background-color: purple; 13 position: relative; 14 } 15 </style> 16 17 <div class="outer"> 18 <div class="inner"></div> 19 </div>
1 <style type="text/css"> 2 .p:hover, 3 .hover { 4 background: purple; 5 } 6 </style> 7 <p class="p" id="target">aaaa bbbbb<span>DDDDDDDDDDDd</span> aaaa lkjlkjdf j</p> 8 <script type="text/javascript"> 9 function addClass(elem, cls) { 10 if(elem.className) { 11 elem.className += ' ' + cls; 12 } else { 13 elem.className = cls; 14 } 15 } 16 17 function removeClass(elem, cls) { 18 var className = ' ' + elem.className + ' '; 19 var reg = new RegExp(' +' + cls + ' +', 'g'); 20 elem.className = className.replace(reg, ' ').replace(/^ +| +$/, ''); 21 } 22 var target = document.getElementById('target'); 23 if(target.attachEvent) { 24 target.attachEvent('onmouseenter', function() { 25 addClass(target, 'hover'); 26 }); 27 target.attachEvent('onmouseleave', function() { 28 removeClass(target, 'hover'); 29 }) 30 } 31 </script>
1 .opacity { 2 opacity: 0.4 3 filter: alpha(opacity=60); /* for IE5-7 */ 4 -ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=60)"; /* for IE 8*/ 5 }
display: inline-block;
*display: inline;
*zoom: 1;
1 /** 2 * 在標準瀏覽器下使用 3 * 1 content內容爲空格用於修復opera下文檔中出現 4 * contenteditable屬性時在清理浮動元素上下的空白 5 * 2 使用display使用table而不是block:能夠防止容器和 6 * 子元素top-margin摺疊,這樣能使清理效果與BFC,IE6/7 7 * zoom: 1;一致 8 **/ 9 10 .clearfix:before, 11 .clearfix:after { 12 content: " "; /* 1 */ 13 display: table; /* 2 */ 14 } 15 16 .clearfix:after { 17 clear: both; 18 } 19 20 /** 21 * IE 6/7下使用 22 * 經過觸發hasLayout實現包含浮動 23 **/ 24 .clearfix { 25 *zoom: 1; 26 }
Flash Of Unstyled Content:用戶定義樣式表加載以前瀏覽器使用默認樣式顯示文檔,用戶樣式加載渲染以後再重新顯示文檔,形成頁面閃爍。解決方法:把樣式表放到文檔的head
建立規則:
做用:
結起來:絕對定位、浮動、根元素都須要調整display
毗鄰的兩個或多個margin會合併成一個margin,叫作外邊距摺疊。規則以下:
z軸上的默認層疊順序以下(從下到上):
如何建立stacking context:
1 <body> 2 <div class="content"> 3 aaaaaa aaaaaa a a a a a a a a 4 </div> 5 </body> 6 7 <style> 8 body { 9 background: #DDD; 10 text-align: center; /* 3 */ 11 } 12 .content { 13 width: 500px; /* 1 */ 14 text-align: left; /* 3 */ 15 margin: 0 auto; /* 2 */ 16 17 background: purple; 18 } 19 </style>
1 <body> 2 <div class="content"> 3 aaaaaa aaaaaa a a a a a a a a 4 </div> 5 </body> 6 7 <style> 8 body { 9 background: #DDD; 10 } 11 .content { 12 width: 500px; /* 1 */ 13 float: left; 14 15 position: relative; /* 2 */ 16 left: 50%; /* 3 */ 17 margin-left: -250px; /* 4 */ 18 19 background-color: purple; 20 } 21 </style>
1 <body> 2 <div class="content"> 3 aaaaaa aaaaaa a a a a a a a a 4 </div> 5 </body> 6 7 <style> 8 body { 9 background: #DDD; 10 position: relative; 11 } 12 .content { 13 width: 800px; 14 15 position: absolute; 16 left: 50%; 17 margin-left: -400px; 18 19 background-color: purple; 20 } 21 </style>
1 <body> 2 <div class="content"> 3 aaaaaa aaaaaa a a a a a a a a 4 </div> 5 </body> 6 7 <style> 8 body { 9 background: #DDD; 10 position: relative; 11 } 12 .content { 13 width: 800px; 14 15 position: absolute; 16 margin: 0 auto; 17 left: 0; 18 right: 0; 19 20 background-color: purple; 21 } 22 </style>
參考資料:6 Methods For Vertical Centering With CSS。 盤點8種CSS實現垂直居中
1 <p class="text">center text</p> 2 3 <style> 4 .text { 5 line-height: 200px; 6 } 7 </style>
Measuring Element Dimension and Location with CSSOM in Windows Internet Explorer 9
例子:鼠標從div#target元素移出時進行處理,判斷邏輯以下:
1 <div id="target"><span>test</span></div> 2 3 <script type="text/javascript"> 4 var target = document.getElementById('target'); 5 if (target.addEventListener) { 6 target.addEventListener('mouseout', mouseoutHandler, false); 7 } else if (target.attachEvent) { 8 target.attachEvent('onmouseout', mouseoutHandler); 9 } 10 11 function mouseoutHandler(e) { 12 e = e || window.event; 13 var target = e.target || e.srcElement; 14 15 // 判斷移出鼠標的元素是否爲目標元素 16 if (target.id !== 'target') { 17 return; 18 } 19 20 // 判斷鼠標是移出元素仍是移到子元素 21 var relatedTarget = event.relatedTarget || e.toElement; 22 while (relatedTarget !== target 23 && relatedTarget.nodeName.toUpperCase() !== 'BODY') { 24 relatedTarget = relatedTarget.parentNode; 25 } 26 27 // 若是相等,說明鼠標在元素內部移動 28 if (relatedTarget === target) { 29 return; 30 } 31 32 // 執行須要操做 33 //alert('鼠標移出'); 34 35 } 36 </script>
同源:兩個文檔同源需知足
跨域通訊:js進行DOM操做、通訊時若是目標與當前窗口不知足同源條件,瀏覽器爲了安全會阻止跨域操做。跨域通訊一般有如下方法
六種基本數據類型
一種引用類型
閉包是在某個做用域內定義的函數,它能夠訪問這個做用域內的全部變量。閉包做用域鏈一般包括三個部分:
閉包常見用途:
重要參考資料:MDN:Functions_and_function_scope
HTML5新增應用程序緩存,容許web應用將應用程序自身保存到用戶瀏覽器中,用戶離線狀態也能訪問。
CACHE MANIFEST
CACHE:
myapp.html
myapp.css
myapp.js
FALLBACK:
videos/ offline_help.html
NETWORK:
cgi/
1 localStorage.setItem('x', 1); // storge x->1 2 localStorage.getItem('x); // return value of x 3 4 // 枚舉全部存儲的鍵值對 5 for (var i = 0, len = localStorage.length; i < len; ++i ) { 6 var name = localStorage.key(i); 7 var value = localStorage.getItem(name); 8 } 9 10 localStorage.removeItem('x'); // remove x 11 localStorage.clear(); // remove all data
1 document.cookie = 'name=qiu; max-age=9999; path=/; domain=domain; secure'; 2 3 document.cookie = 'name=aaa; path=/; domain=domain; secure'; 4 // 要改變cookie的值,須要使用相同的名字、路徑和域,新的值 5 // 來設置cookie,一樣的方法能夠用來改變有效期 6 7 // 設置max-age爲0能夠刪除指定cookie 8 9 //讀取cookie,訪問document.cookie返回鍵值對組成的字符串, 10 //不一樣鍵值對之間用'; '分隔。經過解析得到須要的值
cookieUtil.js:本身寫的cookie操做工具
1. 若是對象有valueOf()方法而且返回元素值,javascript將返回值轉換爲數字做爲結果 2. 不然,若是對象有toString()而且返回原始值,javascript將返回結果轉換爲數字做爲結果 3. 不然,throws a TypeError
全部比較運算符都支持任意類型,可是比較只支持數字和字符串,因此須要執行必要的轉換而後進行比較,轉換規則以下:
1. 若是操做數是對象,轉換爲原始值:若是valueOf方法返回原始值,則使用這個值,不然使用toString方法的結果,若是轉換失敗則報錯
2. 通過必要的對象到原始值的轉換後,若是兩個操做數都是字符串,按照字母順序進行比較(他們的16位unicode值的大小)
3. 不然,若是有一個操做數不是字符串,將兩個操做數轉換爲數字進行比較
1 /** 2 * 跨瀏覽器事件處理工具。只支持冒泡。不支持捕獲 3 * @author (qiu_deqing@126.com) 4 */ 5 6 var EventUtil = { 7 getEvent: function (event) { 8 return event || window.event; 9 }, 10 getTarget: function (event) { 11 return event.target || event.srcElement; 12 }, 13 // 返回註冊成功的監聽器,IE中須要使用返回值來移除監聽器 14 on: function (elem, type, handler) { 15 if (elem.addEventListener) { 16 elem.addEventListener(type, handler, false); 17 return handler; 18 } else if (elem.attachEvent) { 19 var wrapper = function () { 20 var event = window.event; 21 event.target = event.srcElement; 22 handler.call(elem, event); 23 }; 24 elem.attachEvent('on' + type, wrapper); 25 return wrapper; 26 } 27 }, 28 off: function (elem, type, handler) { 29 if (elem.removeEventListener) { 30 elem.removeEventListener(type, handler, false); 31 } else if (elem.detachEvent) { 32 elem.detachEvent('on' + type, handler); 33 } 34 }, 35 preventDefault: function (event) { 36 if (event.preventDefault) { 37 event.preventDefault(); 38 } else if ('returnValue' in event) { 39 event.returnValue = false; 40 } 41 }, 42 stopPropagation: function (event) { 43 if (event.stopPropagation) { 44 event.stopPropagation(); 45 } else if ('cancelBubble' in event) { 46 event.cancelBubble = true; 47 } 48 }, 49 /** 50 * keypress事件跨瀏覽器獲取輸入字符 51 * 某些瀏覽器在一些特殊鍵上也觸發keypress,此時返回null 52 **/ 53 getChar: function (event) { 54 if (event.which == null) { 55 return String.fromCharCode(event.keyCode); // IE 56 } 57 else if (event.which != 0 && event.charCode != 0) { 58 return String.fromCharCode(event.which); // the rest 59 } 60 else { 61 return null; // special key 62 } 63 } 64 };
1 function Shape() {} 2 3 function Rect() {} 4 5 // 方法1 6 Rect.prototype = new Shape(); 7 8 // 方法2 9 Rect.prototype = Shape.prototype; 10 11 // 方法3 12 Rect.prototype = Object.create(Shape.prototype); 13 14 Rect.prototype.area = function () { 15 // do something 16 };
方法1:
方法2:
方法3:
改進:
1 function Rect() { 2 Shape.call(this); 3 }
1 function create(obj) { 2 if (Object.create) { 3 return Object.create(obj); 4 } 5 6 function f() {}; 7 f.prototype = obj; 8 return new f(); 9 }
1 <style> 2 #target { 3 width: 200px; 4 height: 300px; 5 margin: 40px; 6 background-color: tomato; 7 } 8 </style> 9 10 <div id="target"></div> 11 12 <script> 13 function addMask(elem, opacity) { 14 opacity = opacity || 0.2; 15 16 var rect = elem.getBoundingClientRect(); 17 var style = getComputedStyle(elem, null); 18 19 var mask = document.createElement('div'); 20 mask.style.position = 'absolute'; 21 var marginLeft = parseFloat(style.marginLeft); 22 mask.style.left = (elem.offsetLeft - marginLeft) + 'px'; 23 var marginTop = parseFloat(style.marginTop); 24 mask.style.top = (elem.offsetTop - marginTop) + 'px'; 25 mask.style.zIndex = 9999; 26 mask.style.opacity = '' + opacity; 27 mask.style.backgroundColor = '#000'; 28 29 mask.style.width = (parseFloat(style.marginLeft) + 30 parseFloat(style.marginRight) + rect.width) + 'px'; 31 mask.style.height = (parseFloat(style.marginTop) + 32 parseFloat(style.marginBottom) + rect.height) + 'px'; 33 34 elem.parentNode.appendChild(mask); 35 } 36 37 var target = document.getElementById('target'); 38 addMask(target); 39 40 target.addEventListener('click', function () { 41 console.log('click'); 42 }, false); 43 </script>
1 var days = ['日','一','二','三','四','五','六']; 2 var date = new Date(); 3 4 console.log('今天是星期' + days[date.getDay()]);
1 for (var i = 0; i < 5; ++i) { 2 setTimeout(function () { 3 console.log(i + ' '); 4 }, 100); 5 }
不能輸出正確結果,由於循環中setTimeout接受的參數函數經過閉包訪問變量i。javascript運行環境爲單線程,setTimeout註冊的函數須要等待線程空閒才能執行,此時for循環已經結束,i值爲5.五個定時輸出都是5
修改方法:將setTimeout放在函數當即調用表達式中,將i值做爲參數傳遞給包裹函數,建立新閉包
1 for (var i = 0; i < 5; ++i) { 2 (function (i) { 3 setTimeout(function () { 4 console.log(i + ' '); 5 }, 100); 6 }(i)); 7 }
1 function Page() {} 2 3 Page.prototype = { 4 constructor: Page, 5 6 postA: function (a) { 7 console.log('a:' + a); 8 }, 9 postB: function (b) { 10 console.log('b:' + b); 11 }, 12 postC: function (c) { 13 console.log('c:' + c); 14 }, 15 check: function () { 16 return Math.random() > 0.5; 17 } 18 } 19 20 function checkfy(obj) { 21 for (var key in obj) { 22 if (key.indexOf('post') === 0 && typeof obj[key] === 'function') { 23 (function (key) { 24 var fn = obj[key]; 25 obj[key] = function () { 26 if (obj.check()) { 27 fn.apply(obj, arguments); 28 } 29 }; 30 }(key)); 31 } 32 } 33 } // end checkfy() 34 35 checkfy(Page.prototype); 36 37 var obj = new Page(); 38 39 obj.postA('checkfy'); 40 obj.postB('checkfy'); 41 obj.postC('checkfy'); 42
1 function deepClone(obj) { 2 var _toString = Object.prototype.toString; 3 4 // null, undefined, non-object, function 5 if (!obj || typeof obj !== 'object') { 6 return obj; 7 } 8 9 // DOM Node 10 if (obj.nodeType && 'cloneNode' in obj) { 11 return obj.cloneNode(true); 12 } 13 14 // Date 15 if (_toString.call(obj) === '[object Date]') { 16 return new Date(obj.getTime()); 17 } 18 19 // RegExp 20 if (_toString.call(obj) === '[object RegExp]') { 21 var flags = []; 22 if (obj.global) { flags.push('g'); } 23 if (obj.multiline) { flags.push('m'); } 24 if (obj.ignoreCase) { flags.push('i'); } 25 26 return new RegExp(obj.source, flags.join('')); 27 } 28 29 var result = Array.isArray(obj) ? [] : 30 obj.constructor ? new obj.constructor() : {}; 31 32 for (var key in obj ) { 33 result[key] = deepClone(obj[key]); 34 } 35 36 return result; 37 } 38 39 function A() { 40 this.a = a; 41 } 42 43 var a = { 44 name: 'qiu', 45 birth: new Date(), 46 pattern: /qiu/gim, 47 container: document.body, 48 hobbys: ['book', new Date(), /aaa/gim, 111] 49 }; 50 51 var c = new A(); 52 var b = deepClone(c); 53 console.log(c.a === b.a); 54 console.log(c, b);
1 <!doctype html> 2 <html> 3 <head> 4 <meta charset="utf-8"> 5 <title>TEst</title> 6 </head> 7 <body> 8 9 <div> 10 <input type="button" id ="button1" value="1" /> 11 <input type="button" id ="button2" value="2" /> 12 </div> 13 14 <script type="text/javascript"> 15 var btn1 = document.getElementById('button1'); 16 var btn2 = document.getElementById('button2'); 17 18 addListener(btn1, 'click', function (event) { 19 btn1.parentNode.insertBefore(btn2, btn1); 20 }); 21 22 function addListener(elem, type, handler) { 23 if (elem.addEventListener) { 24 elem.addEventListener(type, handler, false); 25 return handler; 26 } else if (elem.attachEvent) { 27 function wrapper() { 28 var event = window.event; 29 event.target = event.srcElement; 30 handler.call(elem, event); 31 } 32 elem.attachEvent('on' + type, wrapper); 33 return wrapper; 34 } 35 } 36 37 </script> 38 </body> 39 </html> 40
1 <!doctype html> 2 <html> 3 <head> 4 <meta charset="utf-8"> 5 <title>TEst</title> 6 </head> 7 <body> 8 9 <span id="target"></span> 10 11 12 <script type="text/javascript"> 13 // 爲了簡化。每個月默認30天 14 function getTimeString() { 15 var start = new Date(); 16 var end = new Date(start.getFullYear() + 1, 0, 1); 17 var elapse = Math.floor((end - start) / 1000); 18 19 var seconds = elapse % 60 ; 20 var minutes = Math.floor(elapse / 60) % 60; 21 var hours = Math.floor(elapse / (60 * 60)) % 24; 22 var days = Math.floor(elapse / (60 * 60 * 24)) % 30; 23 var months = Math.floor(elapse / (60 * 60 * 24 * 30)) % 12; 24 var years = Math.floor(elapse / (60 * 60 * 24 * 30 * 12)); 25 26 return start.getFullYear() + '年還剩' + years + '年' + months + '月' + days + '日' 27 + hours + '小時' + minutes + '分' + seconds + '秒'; 28 } 29 30 function domText(elem, text) { 31 if (text == undefined) { 32 33 if (elem.textContent) { 34 return elem.textContent; 35 } else if (elem.innerText) { 36 return elem.innerText; 37 } 38 } else { 39 if (elem.textContent) { 40 elem.textContent = text; 41 } else if (elem.innerText) { 42 elem.innerText = text; 43 } else { 44 elem.innerHTML = text; 45 } 46 } 47 } 48 49 var target = document.getElementById('target'); 50 51 setInterval(function () { 52 domText(target, getTimeString()); 53 }, 1000) 54 </script> 55 56 </body> 57 </html>
如:[1, [2, [ [3, 4], 5], 6]] => [1, 2, 3, 4, 5, 6]
1 var data = [1, [2, [ [3, 4], 5], 6]]; 2 3 function flat(data, result) { 4 var i, d, len; 5 for (i = 0, len = data.length; i < len; ++i) { 6 d = data[i]; 7 if (typeof d === 'number') { 8 result.push(d); 9 } else { 10 flat(d, result); 11 } 12 } 13 } 14 15 var result = []; 16 flat(data, result); 17 18 console.log(result);
若是瀏覽器支持Array.isArray()能夠直接判斷不然需進行必要判斷
1 /**
2 * 判斷一個對象是不是數組,參數不是對象或者不是數組,返回false
3 *
4 * @param {Object} arg 須要測試是否爲數組的對象
5 * @return {Boolean} 傳入參數是數組返回true,不然返回false
6 */
7 function isArray(arg) {
8 if (typeof arg === 'object') { 9 return Object.prototype.toString.call(arg) === '[object Array]'; 10 } 11 return false; 12 }
1 if (window.addEventListener) { 2 var addListener = function (el, type, listener, useCapture) { 3 el.addEventListener(type, listener, useCapture); 4 }; 5 } 6 else if (document.all) { 7 addListener = function (el, type, listener) { 8 el.attachEvent('on' + type, function () { 9 listener.apply(el); 10 }); 11 }; 12 } 13
做用:瀏覽器功能檢測實現跨瀏覽器DOM事件綁定
優勢:
缺點:
改進:
1 var addListener; 2 3 if (window.addEventListener) { 4 addListener = function (el, type, listener, useCapture) { 5 el.addEventListener(type, listener, useCapture); 6 return listener; 7 }; 8 } 9 else if (window.attachEvent) { 10 addListener = function (el, type, listener) { 11 // 標準化this,event,target 12 var wrapper = function () { 13 var event = window.event; 14 event.target = event.srcElement; 15 listener.call(el, event); 16 }; 17 18 el.attachEvent('on' + type, wrapper); 19 return wrapper; 20 // 返回wrapper。調用者能夠保存,之後remove 21 }; 22 }
1 /** 2 * 判斷對象是否爲函數,若是當前運行環境對可調用對象(如正則表達式) 3 * 的typeof返回'function',採用通用方法,不然採用優化方法 4 * 5 * @param {Any} arg 須要檢測是否爲函數的對象 6 * @return {boolean} 若是參數是函數,返回true,不然false 7 */ 8 function isFunction(arg) { 9 if (arg) { 10 if (typeof (/./) !== 'function') { 11 return typeof arg === 'function'; 12 } else { 13 return Object.prototype.toString.call(arg) === '[object Function]'; 14 } 15 } // end if 16 return false; 17 }
1 /** 2 * 解析query string轉換爲對象,一個key有多個值時生成數組 3 * 4 * @param {String} query 須要解析的query字符串,開頭能夠是?, 5 * 按照application/x-www-form-urlencoded編碼 6 * @return {Object} 參數解析後的對象 7 */ 8 function parseQuery(query) { 9 var result = {}; 10 11 // 若是不是字符串返回空對象 12 if (typeof query !== 'string') { 13 return result; 14 } 15 16 // 去掉字符串開頭可能帶的? 17 if (query.charAt(0) === '?') { 18 query = query.substring(1); 19 } 20 21 var pairs = query.split('&'); 22 var pair; 23 var key, value; 24 var i, len; 25 26 for (i = 0, len = pairs.length; i < len; ++i) { 27 pair = pairs[i].split('='); 28 // application/x-www-form-urlencoded編碼會將' '轉換爲+ 29 key = decodeURIComponent(pair[0]).replace(/\+/g, ' '); 30 value = decodeURIComponent(pair[1]).replace(/\+/g, ' '); 31 32 // 若是是新key,直接添加 33 if (!(key in result)) { 34 result[key] = value; 35 } 36 // 若是key已經出現一次以上,直接向數組添加value 37 else if (isArray(result[key])) { 38 result[key].push(value); 39 } 40 // key第二次出現,將結果改成數組 41 else { 42 var arr = [result[key]]; 43 arr.push(value); 44 result[key] = arr; 45 } // end if-else 46 } // end for 47 48 return result; 49 } 50 51 function isArray(arg) { 52 if (arg && typeof arg === 'object') { 53 return Object.prototype.toString.call(arg) === '[object Array]'; 54 } 55 return false; 56 } 57 /** 58 console.log(parseQuery('sourceid=chrome-instant&ion=1&espv=2&ie=UTF-8')); 59 */
1 /** 2 * 解析一個url並生成window.location對象中包含的域 3 * location: 4 * { 5 * href: '包含完整的url', 6 * origin: '包含協議到pathname以前的內容', 7 * protocol: 'url使用的協議,包含末尾的:', 8 * username: '用戶名', // 暫時不支持 9 * password: '密碼', // 暫時不支持 10 * host: '完整主機名,包含:和端口', 11 * hostname: '主機名,不包含端口' 12 * port: '端口號', 13 * pathname: '服務器上訪問資源的路徑/開頭', 14 * search: 'query string,?開頭', 15 * hash: '#開頭的fragment identifier' 16 * } 17 * 18 * @param {string} url 須要解析的url 19 * @return {Object} 包含url信息的對象 20 */ 21 function parseUrl(url) { 22 var result = {}; 23 var keys = ['href', 'origin', 'protocol', 'host', 24 'hostname', 'port', 'pathname', 'search', 'hash']; 25 var i, len; 26 var regexp = /(([^:]+:)\/\/(([^:\/\?#]+)(:\d+)?))(\/[^?#]*)?(\?[^#]*)?(#.*)?/; 27 28 var match = regexp.exec(url); 29 30 if (match) { 31 for (i = keys.length - 1; i >= 0; --i) { 32 result[keys[i]] = match[i] ? match[i] : ''; 33 } 34 } 35 36 return result; 37 } 38
1 /** 2 * 查詢指定窗口的視口尺寸,若是不指定窗口,查詢當前窗口尺寸 3 **/ 4 function getViewportSize(w) { 5 w = w || window; 6 7 // IE9及標準瀏覽器中可以使用此標準方法 8 if ('innerHeight' in w) { 9 return { 10 width: w.innerWidth, 11 height: w.innerHeight 12 }; 13 } 14 15 var d = w.document; 16 // IE 8及如下瀏覽器在標準模式下 17 if (document.compatMode === 'CSS1Compat') { 18 return { 19 width: d.documentElement.clientWidth, 20 height: d.documentElement.clientHeight 21 }; 22 } 23 24 // IE8及如下瀏覽器在怪癖模式下 25 return { 26 width: d.body.clientWidth, 27 height: d.body.clientHeight 28 }; 29 }
1 /** 2 * 獲取指定window中滾動條的偏移量,如未指定則獲取當前window 3 * 滾動條偏移量 4 * 5 * @param {window} w 須要獲取滾動條偏移量的窗口 6 * @return {Object} obj.x爲水平滾動條偏移量,obj.y爲豎直滾動條偏移量 7 */ 8 function getScrollOffset(w) { 9 w = w || window; 10 // 若是是標準瀏覽器 11 if (w.pageXOffset != null) { 12 return { 13 x: w.pageXOffset, 14 y: w.pageYOffset 15 }; 16 } 17 18 // 老版本IE,根據兼容性不一樣訪問不一樣元素 19 var d = w.document; 20 if (d.compatMode === 'CSS1Compat') { 21 return { 22 x: d.documentElement.scrollLeft, 23 y: d.documentElement.scrollTop 24 } 25 } 26 27 return { 28 x: d.body.scrollLeft, 29 y: d.body.scrollTop 30 }; 31 } 32
1 function richText(text) { 2 var div = document.createElement('div'); 3 div.innerHTML = text; 4 var p = div.getElementsByTagName('p'); 5 var i, len; 6 7 for (i = 0, len = p.length; i < len; ++i) { 8 if (p[i].getElementsByTagName('img').length === 1) { 9 p[i].classList.add('pic'); 10 } 11 } 12 13 return div.innerHTML; 14 } 15
1 function Event() { 2 if (!(this instanceof Event)) { 3 return new Event(); 4 } 5 this._callbacks = {}; 6 } 7 Event.prototype.on = function (type, handler) { 8 this_callbacks = this._callbacks || {}; 9 this._callbacks[type] = this.callbacks[type] || []; 10 this._callbacks[type].push(handler); 11 12 return this; 13 }; 14 15 Event.prototype.off = function (type, handler) { 16 var list = this._callbacks[type]; 17 18 if (list) { 19 for (var i = list.length; i >= 0; --i) { 20 if (list[i] === handler) { 21 list.splice(i, 1); 22 } 23 } 24 } 25 26 return this; 27 }; 28 29 Event.prototype.trigger = function (type, data) { 30 var list = this._callbacks[type]; 31 32 if (list) { 33 for (var i = 0, len = list.length; i < len; ++i) { 34 list[i].call(this, data); 35 } 36 } 37 }; 38 39 Event.prototype.once = function (type, handler) { 40 var self = this; 41 42 function wrapper() { 43 handler.apply(self, arguments); 44 self.off(type, wrapper); 45 } 46 this.on(type, wrapper); 47 return this; 48 }; 49
1 <ul id="target"> 2 <li>1</li> 3 <li>2</li> 4 <li>3</li> 5 <li>4</li> 6 </ul> 7 8 <script> 9 var target = document.getElementById('target'); 10 var i; 11 var frag = document.createDocumentFragment(); 12 13 for (i = target.children.length - 1; i >= 0; --i) { 14 frag.appendChild(target.children[i]); 15 } 16 target.appendChild(frag); 17 </script>
1 // define 2 (function (window) { 3 function fn(str) { 4 this.str = str; 5 } 6 7 fn.prototype.format = function () { 8 var arg = __1__; 9 return this.str.replace(__2__, function (a, b) { 10 return arg[b] || ''; 11 }); 12 }; 13 14 window.fn = fn; 15 })(window); 16 17 // use 18 (function () { 19 var t = new fn('<p><a href="{0}">{1}</a><span>{2}</span></p>'); 20 console.log(t.format('http://www.alibaba.com', 'Alibaba', 'Welcome')); 21 })(); 22
define部分定義一個簡單的模板類,使用{}做爲轉義標記,中間的數字表示替換目標,format實參用來替換模板內標記
橫線處填:
1 <form id="target"> 2 <select name="age"> 3 <option value="aaa">aaa</option> 4 <option value="bbb" selected>bbb</option> 5 </select> 6 <select name="friends" multiple> 7 <option value="qiu" selected>qiu</option> 8 <option value="de">de</option> 9 <option value="qing" selected>qing</option> 10 </select> 11 <input name="name" value="qiudeqing"> 12 <input type="password" name="password" value="11111"> 13 <input type="hidden" name="salery" value="3333"> 14 <textarea name="description">description</textarea> 15 <input type="checkbox" name="hobby" checked value="football">Football 16 <input type="checkbox" name="hobby" value="basketball">Basketball 17 <input type="radio" name="sex" checked value="Female">Female 18 <input type="radio" name="sex" value="Male">Male 19 </form> 20 21 22 <script> 23 24 /** 25 * 將一個表單元素序列化爲可提交的字符串 26 * 27 * @param {FormElement} form 須要序列化的表單元素 28 * @return {string} 表單序列化後的字符串 29 */ 30 function serializeForm(form) { 31 if (!form || form.nodeName.toUpperCase() !== 'FORM') { 32 return; 33 } 34 35 var result = []; 36 37 var i, len; 38 var field, fieldName, fieldType; 39 40 for (i = 0, len = form.length; i < len; ++i) { 41 field = form.elements[i]; 42 fieldName = field.name; 43 fieldType = field.type; 44 45 if (field.disabled || !fieldName) { 46 continue; 47 } // enf if 48 49 switch (fieldType) { 50 case 'text': 51 case 'password': 52 case 'hidden': 53 case 'textarea': 54 result.push(encodeURIComponent(fieldName) + '=' + 55 encodeURIComponent(field.value)); 56 break; 57 58 &nbnbsp;case 'radio': 59 case 'checkbox': 60 if (field.checked) { 61 result.push(encodeURIComponent(fieldName) + '=' + 62 encodeURIComponent(field.value)); 63 } 64 break; 65 66 case 'select-one': 67 case 'select-multiple': 68 for (var j = 0, jLen = field.options.length; j < jLen; ++j) { 69 if (field.options[j].selected) { 70 result.push(encodeURIComponent(fieldName) + '=' + 71 encodeURIComponent(field.options[j].value || field.options[j].text)); 72 } 73 } // end for 74 break; 75 76 case 'file': 77 case 'submit': 78 break; // 是否處理? 79 80 default: 81 break; 82 } // end switch 83 } // end for 84 85 return result.join('&'); 86 } 87 88 var form = document.getElementById('target'); 89 console.log(serializeForm(form)); 90 </script>
1 <ul id="nav"> 2 <li><a href="http://11111">111</a></li> 3 <li><a href="http://2222">222</a></li> 4 <li><a href="http://333">333</a></li> 5 <li><a href="http://444">444</a></li> 6 </ul> 7 8 Object: 9 { 10 "index": 1, 11 "name": "111", 12 "link": "http://1111" 13 }
script:
1 var EventUtil = { 2 getEvent: function (event) { 3 return event || window.event; 4 }, 5 getTarget: function (event) { 6 return event.target || event.srcElement; 7 }, 8 // 返回註冊成功的監聽器,IE中須要使用返回值來移除監聽器 9 on: function (elem, type, handler) { 10 if (elem.addEventListener) { 11 elem.addEventListener(type, handler, false); 12 return handler; 13 } else if (elem.attachEvent) { 14 function wrapper(event) { 15 return handler.call(elem, event); 16 }; 17 elem.attachEvent('on' + type, wrapper); 18 return wrapper; 19 } 20 }, 21 off: function (elem, type, handler) { 22 if (elem.removeEventListener) { 23 elem.removeEventListener(type, handler, false); 24 } else if (elem.detachEvent) { 25 elem.detachEvent('on' + type, handler); 26 } 27 }, 28 preventDefault: function (event) { 29 if (event.preventDefault) { 30 event.preventDefault(); 31 } else if ('returnValue' in event) { 32 event.returnValue = false; 33 } 34 }, 35 stopPropagation: function (event) { 36 if (event.stopPropagation) { 37 event.stopPropagation(); 38 } else if ('cancelBubble' in event) { 39 event.cancelBubble = true; 40 } 41 } 42 }; 43 var DOMUtil = { 44 text: function (elem) { 45 if ('textContent' in elem) { 46 return elem.textContent; 47 } else if ('innerText' in elem) { 48 return elem.innerText; 49 } 50 }, 51 prop: function (elem, propName) { 52 return elem.getAttribute(propName); 53 } 54 }; 55 56 var nav = document.getElementById('nav'); 57 58 EventUtil.on(nav, 'click', function (event) { 59 var event = EventUtil.getEvent(event); 60 var target = EventUtil.getTarget(event); 61 62 var children = this.children; 63 var i, len; 64 var anchor; 65 var obj = {}; 66 67 for (i = 0, len = children.length; i < len; ++i) { 68 if (children[i] === target) { 69 obj.index = i + 1; 70 anchor = target.getElementsByTagName('a')[0]; 71 obj.name = DOMUtil.text(anchor); 72 obj.link = DOMUtil.prop(anchor, 'href'); 73 } 74 } 75 76 alert('index: ' + obj.index + ' name: ' + obj.name + 77 ' link: ' + obj.link); 78 });
1 /** 2 * 數組去重 3 **/ 4 function normalize(arr) { 5 if (arr && Array.isArray(arr)) { 6 var i, len, map = {}; 7 for (i = arr.length; i >= 0; --i) { 8 if (arr[i] in map) { 9 arr.splice(i, 1); 10 } else { 11 map[arr[i]] = true; 12 } 13 } 14 } 15 return arr; 16 } 17 18 /** 19 * 用100個隨機整數對應的字符串填充數組。 20 **/ 21 function fillArray(arr, start, end) { 22 start = start == undefined ? 1 : start; 23 end = end == undefined ? 100 : end; 24 25 if (end <= start) { 26 end = start + 100; 27 } 28 29 var width = end - start; 30 var i; 31 for (i = 100; i >= 1; --i) { 32 arr.push('' + (Math.floor(Math.random() * width) + start)); 33 } 34 return arr; 35 } 36 37 var input = []; 38 fillArray(input, 1, 100); 39 input.sort(function (a, b) { 40 return a - b; 41 }); 42 console.log(input); 43 44 normalize(input); 45 console.log(input);