******************************* Chapter 11 DOM擴展 *******************************css
主要的擴展是 選擇符API 和 HTML5html
選擇符API:node
document.querySelector('.img');web
document.querySelector('#test');算法
document.querySelectorAll('a');chrome
//這個方式瀏覽器支持不多,返回是否能夠查詢獲得的結果編程
document.matchesSelector('a.test');//true/falsecanvas
元素遍歷:跨域
//這種方式就不會考慮後臺元素的 空白文本節點了,數組
//由於使用 childNodes\firstChild\lastChild 不一樣的瀏覽器效果不同
function eleAll(ele){
var child=ele.firstElementChild;
while(child!=ele.lastElementChild){
//do
child=ele.nextElementSibling;
}
}
HTML5:
與類相關的擴充:
//IE9+
document.getElementsByClassName('p');//返回NodeList
//獲取元素的 class ,返回字符串
div.className;//'cls '
//類的數組 Firefox 和Chrome 支持classList
div.classList;//['cls']
div.classList.remove('cls');
div.classList.add('newcls');
div.classList.toggle('cls');
div.classList.contains('cls');
焦點管理:
document.activeElement;//返回獲取到焦點的元素
ele.hasFocus();//是否獲取到焦點
HTMLDocument 的變化:
readyState:
document.readyState;//loading\complete
compatMode:
兼容模式:CSS1Compat(標準模式)、BackCompat(混雜模式)
document.compatMode;//CSS1Compat
head: Chrome 和 Safari 5
var head = document.head || document.getElementsByTagName('head')[0];
字符集屬性:
document.charset;//"UTF-8"
document.defaultCharset;//默認操做系統設置,通常少有瀏覽器支持
自定義數據屬性:
使用前綴 data-
dataset 獲取自定義屬性
Firefox\chrome\IE11+ 支持
<div id='divtest' data-appid='test'></div>
var div = document.getElementById('divtest');
console.log(div.dataset.appid);
//自定義設置 data-test
div.dataset.test='hah';
console.log(div.dataset.test);
插入標記:
//大多數瀏覽器不支持的寫法,IE8以及以前能夠執行,可是腳本<script> 以前必須有 ‘做用域元素’
div.innerHTML='_<script>alert(1);<\/script>';
IE8的支持 window.toStaticHTML():
var text = '<a href="#" onclick="alert(1);">test</a>';
text = window.toStatocHTML(text);
console.log(text);//<a href="#">test</a>
//使用新的html 元素替換掉div 元素
div.outerHTML='<p>1232323</p>';
insertAdjacentHTML():
div.insertAdjacentHTML('beforebegin','<p>1111</p>');// div以前同輩元素
div.insertAdjacentHTML('afterbegin','<p>2222</p>');// div 子元素第一個
div.insertAdjacentHTML('beforeend','<p>3333</p>');// div 子元素最後一個
div.insertAdjacentHTML('afterend','<p>4444</p>');// div 以後的同輩節點
內存與性能問題:
使用innerHTML\outerHTML\insertAdjacentHTML 刪除元素時候,元素以前綁定的事件關係並無刪除,會佔用內存
scrollIntoView:
div.scrollIntoView();
專有擴展:
文檔模式:
<meta http-equiv="X-UA-Compatible" content="IE=Edge" />
<meta http-equiv="X-UA-Compatible" content="IE=7" />
<meta http-equiv="X-UA-Compatible" content="IE=EmulateIE7" />
alert(document.documentMode);//返回IE 文檔模式版本號 五、六、七、八、九、11
children:
ele.children;//只包含元素節點,排除文本節點
contains():
document.documentElement.contains(d);
compareDocumentPosition:
1: 無關
2:居前
4:居後
8:包含
16:被包含
document.documentElement.compareDocumentPosition(document.body);//20 = 16+4
//兼容性的 contains
function contains(refNode, otherNode) {
if (typeof refNode.contains == 'function' && (!client.engin.webkit || client.engin.webkit >= 522)){
return refNode.contains(otherNode);
} else if (typeof refNode.compareDocumentPosition == 'function') {
return !!(refNode.compareDocumentPosition(otherNode));
} else {
var node = otherNode.parentNode;
do {
if (refNode == node) {
return true;
} else {
node = node.parentNode;
}
} while (node != null);
}
}
插入文本:
//這種方式能夠過濾掉 全部的 html 標籤,只剩下文本
var div = document.getElementById('div1');
div.innerText = div.innerText;
//firefox 不支持 innerText, 可是可使用 textContent
function getInnerText(ele) {
return typeof ele.textContent == 'string' ? ele.textContent : ele.innerText;
}
function setInnerText(ele, txt) {
if (typeof ele.textContent == 'string') {
ele.textContent = txt;
} else {
ele.innerText = txt;
}
}
outerText:
div.outerText='test';//文本替換div元素
滾動:
//如下方法不經常使用,支持度很差
div.scrollIntoViewIfNeeded(true);//當前元素在視口不可見時滾動,設置爲true,元素儘可能顯示在視口中部
div.scrollByLines(2);
div.scrollByPage(1)
******************* Chapter 12 DOM2和DOM3 *****************
DOM變化:
document.implementation.hasFeature('COe','1');//無論怎樣都是返回true
針對XML命名空間的變化:
其餘方面的變化:
DocumentType類型的變化:
document.doctype.publicId;
document.doctype.systemId;
document.internalSubset;//幾乎不會用到
//相似cloneNode()
var newNode = document.importNode(oldNode,true);
document.body.appendChild(newNode);
//IE 使用 parentWindow
document.defaultView||document.parentWindow;
document.body.isSupported('HTML','2.0')
var div = document.createElement("div");
div.setUserData('name', 'test', function (operation, key, value, src, dest) {
//operation: 1.複製 2.導入 3.刪除 4.重命名
})
var iframe = document.getElementById('myFrame');
//IE8以前 contentWindow
var doc = ifame.contentDocument || iframe.contentWindow.document;
樣式:
訪問元素的樣式:
DOM樣式屬性和方法:
var ele = document.getElementById('div1');
var prop, val;
for (var i = 0; i < ele.style.length; i++) {
prop = ele.style[i];
val = ele.style.getPropertyCSSValue(prop);
}
計算的樣式:
//null 表示不須要僞元素
var comStyle = document.defaultView.getComputedStyle(ele, null);
console.log(comStyle.color);//獲取最終實際的值,有效果的值
//IE
var IDComStyle = ele.currentStyle;
console.log(comStyle.color);//獲取最終實際的值,有效果的值
操做樣式表:
document.styleSheets
var link = document.getElementsByTagName("link")[0];
var sheet = link.sheet || link.styleSheet;//IE 使用styleSheet
//以上的等價表示
document.styleSheets;
//stylesheets
var sheet = document.stylesheets[0];
var rules = sheet.cssRules || sheet.rules;
var rule = rules[0];
rule.style.backgroundColor = 'red';
//deleteRule
function deleteRule(sheet, index) {
if (sheet.deleteRule) {
sheet.deleteRule(index);
} else if (sheet.removeRule) {//IE
sheet.removeRule(index);
}
}
元素大小:
1. 偏移量
offsetTop: 元素上邊框與包含元素在內的上內邊框的距離
offsetLeft: 元素左邊框與包含元素在內的左內邊框的距離
offsetWidth: 元素垂直方向上佔用的空間大小。包括滾動條
offsetHeight: 元素水平方向上佔用的空間大小。包括滾動條
以上都是隻讀屬性,儘可能避免重複訪問這些屬性,由於每次都會重複計算,影響性能
function getEleLeft(ele) {
var left = ele.offsetLeft;
var curEle = ele.offsetParent;
while (curEle != null) {
left += curEle.offsetLeft;
curEle = ele.offsetParent;
}
return left;
}
function getEleTop(ele) {
var top = ele.offsetTop;
var curEle = ele.offsetParent;
while (curEle != null) {
top += curEle.offsetTop;
curEle = ele.offsetParent;
}
return top;
}
2. 客戶區大小
clientWidth\clientHeight
var ele = document.getElementById("");
ele.clientWidth;//內容寬度+內邊距
ele.clientHeight;//內容高度+內邊距
//獲取視口的大小
function getViewport() {
if (document.compatMode == 'BackCompat') {
return {
width: document.body.clientWidth,
height: document.body.clientHeight
};
} else {
return {
width: document.documentElement.clientWidth,
height: document.documentElement.clientHeight
};
}
}
3. 滾動大小
ele.scrollHeight;//沒有滾動條的狀況,元素內容實際的總高度
ele.scrollWidth;//沒有滾動條的狀況,元素內容實際的總寬度
ele.scrollTop;//被隱藏在內容區域上方的高度
ele.scrollLeft;//被隱藏在內容區域左側的寬度
//使元素滾動到頂部
function scrollToTop(ele) {
if (ele.scrollTop != 0) {
ele.scrollTop = 0;
}
}
4. 肯定元素的大小
function getBoundingClientRect(ele) {
var scrollTop = document.documentElement.scrollTop;
var scrollLeft = document.documentElement.scrollLeft;
if (typeof arguments.callee.offset != 'number') {
var temp = document.createElement("div");
temp.style.cssTex = "position:absolute;left:0;top:0;";
document.body.appendChild(temp);
arguments.callee.offset = -temp.getBoundingClientRect().top - scrollTop;
document.body.removeChild(temp);
temp = null;
}
var rect = ele.getBoundingClientRect();
var offset = arguments.callee.offset;
return {
left: rect.left + offset,
right: rect.right + offset,
top: rect.top + offset,
bottom: rect.bottom + offset
};
//console.log(arguments.callee.offset);
}
遍歷:
IE不支持DOM遍歷
NodeIterator:
//獲取全部的元素
var itor = document.createNodeIterator(document, NodeFilter.SHOW_ALL, null, false);
var node = itor.nextNode();
while (node) {
console.log(node.tagName);
node = itor.nextNode();
}
//獲取div下面的 p 元素, 自定義過濾器
var div = document.getElementById("div");
var filter = function (node) {
return node.tagName.toLowerCase() == 'p' ? NodeFilter.FILTER_ACCEPT : NodeFilter.FILTER_SKIP;
};
var iter = document.createNodeIterator(div, NodeFilter.SHOW_ELEMENT, filter, false);
TreeWalker:
更自由,更靈活的方式;
var div = document.getElementById("div");
var filter = function (node) {
return node.tagname.tolowercase() == 'p' ? nodefilter.filter_accept : nodefilter.filter_skip;
};
var walker = document.createTreeWalker(div, filter, NodeFilter.SHOW_ELEMENT, false);
walker.firstChild();
walker.nextSibling();
var node = walker.firstChild();
while (node) {
console.log(node.tagName);
node = walker.nextSibling();
}
範圍:
DOM中的範圍:
Range實例
var range1 = document.createRange(),
range2 = document.createRange();
var p = document.getElementById('testP');
range1.selectNode(p);//包括 p 元素
range2.selectNodeContents(p);//只是包括 p 元素的子節點
基本操做
var startNode = p.firstChild.firstChild;
var endNode = p.lastChild;
range1.setStart(startNode, 2);
range1.setEnd(endNode, 3);
var fragment = range1.extractContents();
p.parentNode.appendChild(fragment);
fragment = range1.cloneContents();
range1.deleteContents();
var span = document.createElement("span");
range1.insertNode(span);
range1.surroundContents(span);//將先執行 extractContents(), 將獲取的片斷插入 span 中
range1.collapse(true);//true 表示摺疊到起點 false 摺疊到終點
range1.collapsed;//查詢是否摺疊
range1.compareBoundaryPoints(Range.START_TO_START, range2);//-1:沒有任何關係 0:相等 1:包含關係
//複製範圍
var newRange = range1.cloneRange();
//清理範圍
range1.detach();
range1 = null;
IE8及更早版本中的範圍
var ieRange = document.body.createTextRange();
var canFound = ieRange.findText("hello");//true/false
console.log(ieRange.text);
var canFound = ieRange.findText("hello", 1);//true/false 1:向前搜索 -1: 向後搜索
ieRange.moveToElementText(p);
ieRange.htmlText;
ieRange.moveStart('word', 2);
ieRange.moveEnd('character', 2);
ieRange.expand('hello');
ieRange.pasteHTML('<p>test</p>');
ieRange.collapse(true);
var isCollapsed = (ieRange.boundingWidth == 0);//是否摺疊
ieRange.compareEndpoints("StartToStart", range2);
ieRange.isEqual(range2);
ieRange.inRange(range2);
var newRange = ieRange.duplicate();//複製
********************* Chapter 13 事件 *********************
事件流:
事件冒泡:IE
IE九、Firefox、Chrome、Safari 事件一直冒泡到 window 對象
事件捕獲:
由於老版本瀏覽器不支持,因此不多使用事件捕獲,建議都使用事件冒泡
DOM事件流:
捕獲階段-->處於目標階段-->冒泡階段
事件處理程序:
HTML事件處理程序:
<!--<input type="button" name="name" value="btn" onclick="alert(this.value)" />-->
<!--動態擴展性-->
<input type="button" name="name" value="btn" onclick="alert(value)" />
<!--表單的擴展性-->
<form action="/" method="post">
<input type="text" name="userName" value="admin" />
<input type="button" name="name" value="btnGo" onclick="alert(userName.value)" />
</form>
<!--普通方式-->
<!--<input type="button" name="name" value="btn" onclick="show(this)" />-->
<!--這種是保險的方式,防止方法還沒加載處理,就執行了點擊事件,也是缺點之一 -->
<input type="button" name="name" value="btn" onclick="try {show(this);} catch (e) { }" />
DOM0級事件處理程序:
var btn = document.getElementById('btn');
btn.onclick = function () {
console.log(this.id);//this 指向的是當前的元素
}
DOM2級事件處理程序:
//addEventListener能夠同時綁定多個事件
var btn = document.getElementById('btn');
btn.addEventListener('click', function () {
console.log(this, id);
}, false);//true:表示捕獲節點觸發 false:表示冒泡階段觸發
btn.addEventListener('click', function () {
console.log(this.name);
}, false);//true:表示捕獲節點觸發 false:表示冒泡階段觸發
//removeEventListenerc 操做的時候只能使用命名的方式
var handler = function () {
console.log(this.id);
}
btn.addEventListener('click', handler, false);
btn.removeEventListenerc('click', handler,false);
IE事件處理程序:
var handler = function () {
console.log(this == window);//attachEvent 時候,this 是全局做用域 window
};
btn.attachEvent('onclick', handler);//attachEvent 若是同時綁定多個方法,就會倒序執行
btn.detachEvent('onclick');
跨瀏覽器的事件處理程序:
var EventUtil = {
addHandler: function (ele, type, handler) {
if (ele.addEventListener) {
ele.addEventListener(type, handler, false);
} else if (ele.attachEvent) {
ele.attachEvent('on' + type, handler);
} else {
ele['on' + type] = handler;
}
},
removeHandler: function (ele, type, handler) {
if (ele.removeEventListener) {
ele.removeEventListener(type, handler, false);
} else if (ele.detachEvent) {
ele.detachEvent('on' + type, handler);
} else {
ele['on' + type] = null;//DOM0 級方式
}
}
}
事件對象:
DOM中的事件對象:
var btn = document.getElementById('btn');
btn.onclick = function () {
//event.preventDefault();//阻止默認事件,這個只有在 cancellable =true 的時候有用
//event.stopPropagation();//阻止事件冒泡
alert(event.eventPhase);//click 2 處於目標階段
//alert(event.type);//click
//console.log(this.id);//this 指向的是當前的元素
}
document.body.addEventListener('click', function () {
alert(event.eventPhase);//1
}, true);//捕獲階段
document.body.onclick = function () {
alert(event.eventPhase);//3 冒泡階段
}
IE中的事件對象:
btn.onclick = function () {
var e = window.event;
e.cancelable = true;//IE 取消冒泡事件
e.returnValue = false;//IE取消默認行爲
}
跨瀏覽器的事件對象:
var EventUtil = {
getClipboardText: function (event) {
var clipData = (event.clipboarData || window.clipboardData);
return clipData.getData('text');
},
setClipboardText: function (event,value) {
if (event.clipboarData) {
return event.clipboarData.setData("text/plain", value);
} else if (window.clipboardData) {
return window.clipboardData.setData("text", value);
}
},
getWheelDelta: function (event) {
if (event.wheelDelta) {
return client.engine.opera && client.engine.opera < 9.5 ? -event.wheelDelta : event.wheelDelta;
} else {
return -event.detail * 40;//Firefox
}
},
getButton: function () {
if (document.implementation.hasFeature('MouseEvents', '2.0')) {
return event.button;
} else {
//IE
switch (event.button) {
case 0:
case 1:
case 3:
case 5:
case 7:
return 0;
case 2:
case 6:
return 2;
case 4:
return 1;
}
}
},
//對於鼠標事件的 mouseout和mouseover
getRelatedTarget: function (event) {
if (event.getRelatedTarget) {
return RelatedTarget;
} else if (event.toElement) {
return event.toElement;//IE mouseout
} else if (event.fromElement) {
return event.fromElement;//IE mouseover
} else {
return null;
}
},
getEvent: function (event) {
return event ? event : window.event;
},
getTarget: function (event) {
return event.target || event.srcElement;
},
preventDefault: function (event) {
if (event.preventDefault) {
event.preventDefault();
} else {
event.returnValue = false;
}
},
stopPropagation: function (event) {
if (event.stopPropagation) {
event.stopPropagation();
} else {
event.cancelBubble = true;
}
},
addHandler: function (ele, type, handler) {
if (ele.addEventListener) {
ele.addEventListener(type, handler, false);
} else if (ele.attachEvent) {
ele.attachEvent('on' + type, handler);
} else {
ele['on' + type] = handler;
}
},
removeHandler: function (ele, type, handler) {
if (ele.removeEventListener) {
ele.removeEventListener(type, handler, false);
} else if (ele.detachEvent) {
ele.detachEvent('on' + type, handler);
} else {
ele['on' + type] = null;//DOM0 級方式
}
}
}
事件類型:
UI事件:
load\unload\abort\error\select\resize\scroll\
img 也可使用 load 事件
焦點事件:
blur(不支持冒泡)\DOMFocusIn\DOMFocusOut\focus(不支持冒泡)\focusin(支持冒泡)\focusout
鼠標與滾輪事件:
click\dbclick\mousedown\mouseenter(不冒泡)\mouseleave(不冒泡)\mousemove\mosueout\mouseover\mouseup
mousewheel
clientX\clientY:相對視口的位置
pageX\pageY:相對頁面的位置
screenX\screenY:相對屏幕的位置
event.shiftKey\event.ctrlKey\event.altKey\event.metaKey(IE8不支持)
鼠標按鈕:
event.button: 0:左鍵 1:中間滾輪 2:右鍵
mousewheel:
event.wheelDelta:120倍數表示向前滾動,-120倍數表示向後滾動,Opera 是相反的
Firefox使用的DOMMouseScroll事件:-3表示向前滾動,3表示想後滾動
觸摸設備:
不支持dbclick
無障礙性問題:
屏幕閱讀器沒法觸發mousedown事件;
不要使用mouseover;
不要使用dbclick
鍵盤與文本事件:
keydown(任意鍵)\keypress(字符鍵)\keyup\
event.keyCode
keypress事件:event.charCode
DOM3級變化:不推薦
不在包含charCode,而是使用key\char
location|keyLocation
getModifierState('Shift')
textInput事件:IE9+
對於可編輯區域輸入實際字符纔會觸發,
event.data 返回實際字符;
event.inputMethod 返回輸入模式
複合事件:IE9+惟一支持,不推薦
compositionstart\compositionupdate\compositionend
變更事件:
刪除節點:
DOMNodeRemoved\DOMSubtreeModified\DOMNodeRemoved\DOMNodeRemovedFromDocument
插入節點:
DOMNodeinserted\DOMSubtreeModified\DOMNodeInsertedDocument
HTML5事件:
contextmenu 右鍵菜單事件
var div = document.getElementById("div");
//右鍵菜單點擊事件
div.addEventListener('contextmenu',function(event){
event = event||window.event;
//取消右鍵菜單默認事件
event.preventDefault();
var menu = document.getElementById("menu");
menu.style.left=event.clientX+'px';
menu.style.top=event.clientY+'px';
menu.style.visibility='visible';
},false);
var menu = document.getElementById("menu");
// menu.onclick=function(){
// event.stopPropagation();
// }
menu.addEventListener('click',function(){
event.stopPropagation();
},false)
document.onclick=function(){
var menu = document.getElementById("menu");
menu.style.visibility='hidden';
}
beforeunload事件
//離開頁面以前的提示
window.addEventListener('beforeunload',function(){
var msg ="are you sure to go ...";
event.returnValue=msg;
return msg;
},false);
DOMContentLoaded 事件
DOM樹造成以後當即調用,而且會在load以前
document.addEventListener('DOMContentLoaded',function(){
alert('ok');
},false);
//對於不支持DOMContentLoaded 的可使用以下方式替代
setTimeout(function(){},0);
readystatechange 事件
document.addEventListener('readystatechange',function(event){
if(document.readyState=='interactive' || document.readyState=='complete'){
alert('loaded...');
}
},false);
//動態添加 script 元素
var script = document.createElement('script');
script.addEventListener('readystatechange', function (event) {
if (script.readyState == 'loaded' || event.script == 'complete') {
script.removeEventListener('readystatechange', arguments.callee, false);
}
}, false)
script.src = 'test.js';
document.body.appendChild(script);
pageshow和pagehide事件:
bfcache 用來緩存頁面,當時用了瀏覽器 ‘前進’、‘後退’的時候
不管頁面是否來自緩存,都會執行pageshow 事件,都是在load事件以後執行
event.persisted 表示是否來自bfcache緩存
pagehide 在頁面卸載以前觸發
指定了onunload事件的頁面會被自動排除在 bfcache 以外
//注意這兩個事件都是綁定到 window 對象上,實際目標是document
window.addEventListener('pageshow', function () {
console.log(event.persisted);
}, false);
hashchange事件:
//url 改變的時候觸發
window.addEventListener('hashchange', function (event) {
console.log(event.oldURL);
console.log(event.newURL);
console.log(location.hash);//考慮兼容性,推薦使用
}, false);
設備事件:
orientationchange 事件:
window.addEventListener('orientationchange', function (event) {
console.log(window.orientation);
}, false);
觸摸與手勢事件:
觸摸事件:
touchstart
touchmove
touchend
touchcancel
手勢事件:
gesturestart
gesturechange
gestureend
event.rotate\event.scale
內存和性能:
事件委託:
經過事件冒泡,只爲上層元素添加事件,經過判斷元素目標執行事件
也能夠直接爲 document 對象添加事件處理程序
移除事件處理程序:
var btn = document.getElementById('btn');
btn.onclick = function () {
//移除處理事件
btn.onclick = null;
//...替換btn操做
}
模擬事件:
DOM中的事件模擬:
模擬鼠標事件:
var btn = document.getElementById('btn');
var event = document.createEvent("MouseEvents");
event.initMouseEvent("click", true, true, document.defaultView, 0, 0, 0, 0, 0, false, false, false, false, 0, null);
//觸發事件
btn.dispatchEvent(event);
IE中的事件模擬:
var btn = document.getElementById('btn');
var event = document.createEventObject();
event.screenX = 100;
event.screenY = 0;
event.clientX = 0;
event.clientY = 0;
event.ctrlkey = false;
event.altKey = false;
event.shiftKey = false;
event.button = 0;
btn.fireEvent('onclick', event);
********************* Chapter 14 表單腳本 *********************
表單的基礎知識:
document.forms[0];
document.forms['form2'];
提交表單:
var form1 = document.getElementById("form1");
form1.submit();//這種方式不會觸發 submit 事件
document.forms[0].addEventListener("submit", function (event) {
alert('1');
//組織表單提交的默認事件
event.preventDefault();
}, false);
重置表單:
reset
表單字段:
form.elements[0]
form.elements['txtName']
//修改元素類型
form1.elements["t"].type = 'checkbox';
focus()\blur():
<input type="text" name="t" value="1" autofocus />
文本框腳本:
選擇文本:
select():
//選中輸入框文本
form1.elements["t"].select();
selectionStart\selectionEnd:
//獲取文本選中位置
alert(form1.elements["t"].selectionStart +","+ form1.elements["t"].selectionEnd);
//IE的方式
document.selection.createRange().text
setSelectionRange():
//設置選擇區域
form1.elements["t"].setSelectionRange(1, 2);
//通用方式
function setSelection(txt, start, end) {
if (txt.setSelectionRange) {
txt.setSelectionRange(start, end);
} else if (txt.createTextRange) {//IE8及如下
var range = txt.createTextRange();
range.collapse(true);
range.moveStart("character", start);
range.moveEnd("character", end - start);
range.select();
}
txt.focus();
}
過濾輸入:
var txt = document.getElementById('txt');
txt.onkeypress = function (event) {
//除了 Ctrl 鍵和 其餘字符輸入鍵,都屏蔽掉
if (!/\d/.test(String.fromCharCode(event.charCode)) && event.charCode > 9 && !event.ctrlKey) {
event.preventDefault();
}
}
操做剪貼板:
cop\cut\paste
//獲取剪貼板內容
var EventUtil = {
getClipboardText: function (event) {
var clipData = (event.clipboarData || window.clipboardData);
return clipData.getData('text');
},
setClipboardText: function (event,value) {
if (event.clipboarData) {
return event.clipboarData.setData("text/plain", value);
} else if (window.clipboardData) {
return window.clipboardData.setData("text", value);
}
}
}
自動切換焦點:
(function () {
function tab(event) {
var target = window.event.srcElement;
if (target.value.length == target.maxLength) {
var form = target.form;
for (var i = 0,len = form.elements.length; i < len ; i++) {
if (form.elements[i] == target) {
if (form.elements[i+1]) {
form.elements[i+1].focus();
}
return;
}
}
}
}
var a = document.getElementById("a");
var b = document.getElementById("b");
var c = document.getElementById("c");
a.addEventListener("keyup", tab, false);
b.addEventListener("keyup", tab, false);
c.addEventListener("keyup", tab, false);
})();
HTML5約束驗證API:
表單和按鈕均可以設置是否進行默認API的驗證
<form action="/" method="post" novalidate>
<input type="submit" name="btn" value="go" formnovalidate/>
</form>
選擇框腳本:
//添加項
var newOpt = new Option('text', 'value');
sel.add(newOpt,undefined);//推薦
sel.appendChild(newOpt);//IE8及以前bug
//直接移動一項到另外一個selection
var sel = document.getElementById("sel");
var sel2 = document.getElementById("sel2");
sel2.appendChild(sel.options[0]);
//向後移動一項
var opt = sel.options[1];
sel.insertBefore(opt, sel.options[opt.index + 2]);
表單序列化:
function serialize(form) {
var parts = [],
field = null,
optLen,
opt,
optVal;
for (var i = 0, len = form.elements.length; i < len; i++) {
field = form.elements[i];
switch (field.type) {
case "select-one":
case "select-multiple":
if (field.name.length) {
for (var j = 0, optLen = field.options.length; j < optLen; j++) {
opt = field.options[j];
if (opt.selected) {
optVal = "";
if (opt.hasAttribute) {
optVal = (opt.hasAttribute("values") ? opt.value : opt.text);
} else {
optVal = (opt.attributes["value"].specified ? opt.value : opt.text);
}
parts.push(encodeURIComponent(field.name) + "="+
encodeURIComponent(optVal));
}
}
}
break;
case undefined:
case "file":
case 'submit':
case 'reset':
case 'button':
break;
case 'radio':
case 'checkbox':
if (!field.checked) {
break;
}
default:
if (field.name.length) {
parts.push(encodeURIComponent(field.name) + "=" +
encodeURIComponent(field.value));
}
}
}
return parts.join("&");
}
富文本編輯:
designMode:
window.onload = function () {
window.frames['ifm'].document.designMode = 'on';
}
使用 contentEditable 屬性:
var div = document.getElementById("div");
div.contentEditable = 'true';
操做富文本:
window.onload = function () {
window.frames['ifm'].document.designMode = 'on';
//指定富文本指定命令
window.frames['ifm'].document.execCommand("bold",false,null)
//查詢是否可用指定的命令
var res = window.frames['ifm'].document.queryCommandEnabled("bold")
//查詢富文本是否應用了該命令
var res = window.frames['ifm'].document.queryCommandState("bold")
}
富文本選區:
//獲取選區
var selection = window.frames['ifm'].getSelection();
//選區文本
var txt = selection.toString();
//選區範圍
var range = selection.getRangeAt(0);
var span = document.createElement("span");
span.style.backgroundColor = 'yellow';
range.surroundContents(span);
//修改選區的樣式
var range = frames['ifm'].document.selection.createRange();
range.pasteHTML("<span style='color:red;'>" + range.htmlText + "</span>");
表單與富文本:
var form = document.getElementById('form1');
form.addEventListener("submit", function (event) {
var target = event.srcElement;
//提交的時候經過 隱藏域來獲取到 富文本的值後,能夠提交
target.elements['bak'].value = frames['ifm'].document.body.innerHTML;
}, false);
********************* Chapter 15 使用Canvas 繪圖 *********************
基本用法:
<canvas id="canvas" width="200" height="200">該瀏覽器不支持Canvas</canvas>
<hr />
<button onclick="save()">Save</button>
var canvas = document.getElementById("canvas");
if (canvas.getContext) {
var context = canvas.getContext("2d");
context.fillStyle = '#FF0000';
context.fillRect(0, 0, 150, 75);
}
//toDataURL
function save() {
var img = canvas.toDataURL('image/png');
var image = document.createElement("img");
image.src = img;
document.body.appendChild(image);
}
2D上下文:
********************* Chapter 16 HTML5 腳本編程 *********************
跨文檔消息傳遞:XDM
//主頁面負責發送消息
var ifm = document.getElementById("ifm").contentWindow;
ifm.postMessage("msg from here", "http://www.123.com");//來源當前地址文檔
//子頁面 iframe 處理消息
window.onmessage = function (event) {
//確認來自的域
if (event.origin == "http://www.123.com") {
//處理數據
proceeMsg(event.data);
//回發數據 event.source 獲取到的是window 的代理對象
event.source.postMessage("Received", "http://test.123.com");
}
}
原生拖放:
拖放事件:
dragstart
drag
dragend
dragenter
dragover
dragleave\drop
var div = document.getElementById("target");
//目標元素,取消瀏覽器的默認行爲,防止自動打開頁面搜索url
div.addEventListener("dragover", function (event) {
event = event || window.event;
event.preventDefault();
}, false);
div.addEventListener("drop", function (event) {
event = event || window.event;
//獲取 設置的 url ,兼容性(Firefox)
//var url = event.dataTransfer.getData("url") || event.dataTransfer.getData('text/uri-list');
//使用 大寫Text 來獲取,兼容性(Firefox)
var id = event.dataTransfer.getData('Text');
var target = event.srcElement;
target.appendChild(document.getElementById(id));
event.preventDefault();
}, false);
//dataTransfer 的使用
var p = document.getElementById("p");
p.addEventListener("dragstart", function (event) {
event = event || window.event;
event.dataTransfer.setData('text', 'p');//IE中只能設置 'text' 或者 'url'
}, false);
effectAllowed/dropEffect:
event.dataTransfer.effectAllowed = 'move';
event.dataTransfer.dropEffect = 'move';
draggable 可拖動屬性:
<p id="p" draggable="true">to drag div</p>
媒體元素:
歷史狀態管理:
history.pushState({name:"test"},'','test_04.html')
********************* Chapter 17 錯誤處理與調試 *********************
try{
}catch(e){
alert(e.message);
}
//結果: 返回2
function test() {
try {
return 0;
} catch (e) {
return 1;
} finally {
return 2;
}
}
錯誤類型:
Error
EvalError
RangeError
ReferenceError
SyntaxError
TypeError
URIError
throw:
function test1() {
try {
//throw 1;
throw "test error...";
} catch (e) {
console.log(e);//1 test error...
}
}
錯誤事件error:
window.onerror = function (message,url,line) {
alert(message);
}
var a = 1 / 0 + c;//沒有捕捉的錯誤都會觸發 onerror 事件
//圖片也可使用 error 事件
var img = new Image();
img.onerror = function (event) {
}
img.src = 'fd.jpg';//
常見錯誤類型:
function foo(str1, str2) {
//不要使用 if(str2), 由於 傳入0 結果也是 false
if (typeof str2 =="String" ) {
}
}
基本類型使用 typeof 檢測, 對象則使用 instanceof 檢測
記錄日誌到服務端:(高大上)
function logError(sev, msg) {
var img = new Image();
//使用Image 的方式提交錯誤優點:
//1. 避免跨域的問題
//2. 兼容性,全部瀏覽器都支持 Image
//3. 相對於Ajax,出問題的機率更低
img.src = "log.ashx?sev=" + sev + "&msg=" + msg;
}
常見的IE錯誤:
document.onclick = function (event) {
event = event || window.event;
setTimeout(function () {
event.returnValue = false;//IE8 會出現找不到成員
}, 1000);
}
IE對JavaScript 請求資源的 URL 最長不能超過2083個字符限制,URL路徑限制2048
********************* Chapter 18 JavaScript 與 XML *********************
ECMAScript for XML
瀏覽器對XML DOM 的支持
//通常不須要指定 命名空間 和 文檔類型
var xmlDom = document.implementation.createDocument('', 'root', null);
var child = xmlDom.createElement("child");
xmlDom.documentElement.appendChild(child);
DOMParser:
//解析xml
var parser = new DOMParser();
try {
var xml = parser.parseFromString("<root><child/></root>", 'text/xml');
var errors = xml.getElementsByTagName("parsererror");//獲取是否有錯誤節點,錯誤節點名稱 parsererror
if (errors.length > 0) {
throw new Error("parsing error!");
}
console.log(xml.documentElement.tagName);//root
console.log(xml.documentElement.firstChild.tagName);//child
var child = xml.createElement("child");
xml.documentElement.appendChild(child);
var children = xml.getElementsByTagName("child");
console.log(children.length);//2
} catch (e) {
}
XMLSerializer:
var serializer = new XMLSerializer();
var xml = serializer.serializeToString(xmlDom);
console.log(xml);
IE8及以前版本中的XML:
function createDom() {
if (typeof arguments.callee.activeXString != "string") {
var versions = ["MSXML2.DOMDocument.6.0",
"MSXML2.DOMDocument.3.0",
"MSXML2.DOMDocument"];
for (var i = 0, len = versions.length; i < len; i++) {
try{
new ActiveXObject(versions[i]);
arguments.callee.activeXString = versions[i];
break;
}catch(e){
//繼續執行
}
}
}
return new ActiveXObject(arguments.callee.activeXString);
}
var xmlDom = createDom();
xmlDom.loadXML("<root><child/></root>");
if (xmlDom.parseError != 0) {
console.log(xmlDom.parseError.errorCode);
console.log(xmlDom.parseError.line);
console.log(xmlDom.parseError.linepos);
console.log(xmlDom.parseError.reason);
}
console.log(xmlDom.documentElement.tagName);
//添加子節點
xmlDom.documentElement.appendChild(xmlDom.createElement("child"));
序列化獲取xml字符串
var xml = xmlDom.xml;
加載xml文件
var xmlDom = createDom();
xmlDom.async = false;//同步
xmlDom.load("example.xml");
//.....
異步加載和事件綁定
var xmlDom = createDom();
xmlDom.async = true;//異步
xmlDom.onreadystatechange = function () {
if (xmlDom.readyState == 4) {
//.......
}
}
//必須在事件綁定以後 load
xmlDom.load("example.xml");
跨瀏覽器處理XML:
function parseXML(xml) {
var xmlDom = null;
if (typeof DOMParser != 'undefined') {
xmlDom = new DOMParser();
xmlDom.parseFromString(xml, 'text/xml');
var errors = xmlDom.getElementsBytagName("parseerror");
if (errors.length > 0) {
throw new Error("parsing error:"+errors[0].textContent);
}
} else if (typeof ActiveXObject != 'undefined') {
xmlDom = createDom();
xmlDom.loadXML(xml);
if (xmlDom.parseError != 0) {
throw new Error("parsing error:" + xmlDom.parseError.reason);
}
} else {
throw new Error("No Xml parser available");
}
return xmlDom;
}
//解析xmlDom
function serializerXml(xmlDom) {
if (typeof XMLSerializer != 'undefined') {
return (new XMLSerializer()).serializeToString(xmlDom);
} else if (typeof xmlDom.xml != "undefind") {
return xmlDom.xml;
} else {
throw new Error("could'n serialize xmlDom");
}
}
********************* Chapter 19 E4X *********************
********************* Chapter 20 JSON *********************
JavaScript Object Notation
對象的屬性名稱必須使用雙引號
{"name":"kk"}
全局對象JSON:
stringfy():
值爲undefined 的值會被忽略
var book = { "title": "Time", "edtion": '2010', 'price': 20 };
//正常的序列化
console.log(JSON.stringify(book));
//使用縮進的方式
//{
// --"title": "Time",
// --"edtion": "2010",
// --"price": 20
//}
console.log(JSON.stringify(book,null,'--'));
//過濾字段的方式
console.log(JSON.stringify(book, ['title']));// {"title":"Time"} 返回數組中的字段
//使用方法進行過濾
console.log(JSON.stringify(book, function (key, val) {
switch (key) {
case 'price':
return "$" + val + ".00";
case "title":
return undefined;//去掉title
default:
return val;
}
}));//{"edtion":"2010","price":"$20.00"}
toJSON:
var book = {
"title": "Time",
"edtion": '2010',
'price': 20,
toJSON: function () {
return this.title;
}
};
//1. 若是存在 toJSON ,則直接調用 toJSON
//2. 若是存在第二個參數,則應用函數過濾器,傳入的值是第一步返回的值
//3. 對第二步的值進行序列化
//4. 若是提供了第三個參數,執行相應的格式化
console.log(JSON.stringify(book));//"Time"
parse()
//使用第二個參數進行還原操做
JSON.parse(txt, function (key,val) {
if (key == "time") {
return new Date(val);
}
else {
return val;
}
})
********************* Chapter 21 Ajax 與 Comet *********************
XMLHttpRequest 對象:
響應屬性:
responseText:
responseXML:
status:
statusText:
同步請求:
var xhr = new XMLHttpRequest();
//同步請求的方式
xhr.open("get", "test.ashx", false);
xhr.send(null);
if ((xhr.status >= 200 && xhr.status < 300) || xhr.status == 304) {
console.log(xhr.responseText);
} else {
console.log("error: " + xhr.status);
}
異步請求:
readyState:
0:未初始化
1:啓動
2:發送
3:接收
4:完成
var xhr = new XMLHttpRequest();
xhr.onreadystatechange = function () {
if (xhr.readyState == 4) {
if ((xhr.status >= 200 && xhr.status < 300) || xhr.status == 304) {
console.log(xhr.responseText);
} else {
console.log("error: " + xhr.status);
}
}
}
xhr.open("get", "test.ashx", true);
xhr.send();
//能夠設置終止請求
xhr.abort();
xhr = null;
HTTP頭部信息:
Accept
Accept-Charset
Accept-Encoding
Accept-Language
Conenction
Cookie
Host
Referer
User-Agent
GET
var url = "Test.ashx";
addUrlParams(url, "name", "kk");
//get 請求的參數的查詢字符串須要進行 encodeURIComponent編碼
xhr.open("get", url, true);
//設置自定義的請求頭,必須在 open()以後,send()以前
xhr.setRequestHeader("MyHeader", "haha");
xhr.send();
POST
xhr.open("post", "Test.ashx", true);
xhr.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
var form = document.getElementById("f1");
xhr.send(serialize(form));
XMLHttpRequest 2級:
FormData:
var xhr = new XMLHttpRequest();
xhr.onreadystatechange = function () {
if (xhr.readyState == 4) {
if (xhr.status == 200) {
//...
}
}
}
xhr.open('post', 'Tst.ashx', true);
xhr.send(new FormData(document.getElementById('f1')));
超時設定:
xhr.open('post', 'Tst.ashx', true);
xhr.timeout = 1000;//超時設置爲 1s
xhr.ontimeout = function () {
console.log('request over time');
}
xhr.send(new FormData(document.getElementById('f1')));
overrideMimeType() 方法:
xhr.open('post', 'Tst.ashx', true);
//強制響應對象做爲 XML 處理
xhr.overrideMimeType("text/xml");
xhr.send(new FormData(document.getElementById('f1')));
進度事件:
load:
//不須要去檢查 readyState=4
xhr.onload = function () {
if ((xhr.status >= 200 && xhr.status < 300)||xhr.status == 304){
console.log(xhr.responseText);
} else {
//
}
}
progress:
//接收數據期間週期性的觸發
xhr.onprogress = function (event) {
var divStatus = document.getElementById("status");
if (event.lengthComputable) {
divStatus.innerHTML = "Received: " + event.position + ", total:" + event.totalSize + " bytes";
}
}
跨源資源共享:CORS
IE對CORS的實現:
var xdr = new XDomainRequest();
xdr.onload = function () {
console.log(xhr.responseText);
}
xdr.onerror = function () {
console.log("error");
}
xdr.timeout = 1000;
xdr.ontimeout = function () {
console.log("...");
}
//get
xdr.open("get", "http://.......");
xdr.send(null);
//post
xdr.open("post", "http://......");
xdr.contentType = "application/x-www-form-urlencoded";
xdr.send("name=test&age=18");
其餘瀏覽器對CORS的實現:
直接使用 XMLHttpRequest 方式,傳入絕對URL
不能使用 setRequestHeader() 設置自定義頭部
不能發送和接收cookie
調用getAllResponseHeader()方法總會返回空字符
Preflighted Requests:
IE10及以前不支持
帶憑據的請求:
IE10及以前不支持
Access-Control-Allow-Credentials:true
跨瀏覽器的CORS:
function createCROSRequest(method, url) {
var xhr = new XMLHttpRequest();
if ("withCredentials" in xhr) {
xhr.open(method, url, true);
} else if (typeof XDomainRequest != 'undefined') {
xhr = new XDomainRequest();
xhr.open(method, url);
} else {
xhr = null;
}
return xhr;
}
var request = createCROSRequest("get", "http://...");
if (request) {
request.onload = function () {
//處理responseText
};
request.send();
}
其餘跨域技術:
圖像Ping
只能應用於get請求
不能處理響應數據
var img = new Image();
img.onload = img.onerror = function () {
console.log('OK');
}
img.src = "http://www.xx.com?name=test";
JSONP:
JSON with padding
安全性問題得不到保證
function handler(response) {
console.log(response.data);
}
var script = document.createElement("script");
script.src = 'http://www.xx.com?callback=handler';
document.body.insertBefore(script, document.body.firstChild);
Comet:
短輪詢和長輪詢
HTTP流
//IE不兼容
function createStreamClient(url,process,finish) {
var received = 0;
var xhr = new XMLHttpRequest();
xhr.open('get', url, true);
xhr.onreadystatechange = function () {
//不斷從服務端接收數據,readyState 週期性變爲3
if (xhr.readyState == 3) {
var res = xhr.responseText.substring(received);
received += res.length;
process(res);
} else if (xhr.readyState == 4) {
finish(xhr.responseText);
}
}
xhr.send();
return xhr;
}
var client = createStreamClient("http://", function (data) { }, function (data) { })
服務器發送事件:
SSE: Server-Sent Events
IE不兼容
var es = new EventSource("Test.ashx");
//open mesasge error
es.onmessage = function (event) {
var data = event.data;
console.log(es.readyState);//0:正在鏈接 1:打開了鏈接 2:關閉了鏈接
console.log(data);
}
//es.close();
//服務端
public void ProcessRequest(HttpContext context)
{
//var header = context.Request.Headers["MyHeader"];
//context.Response.Headers["MyHeader"] = header;
context.Response.ContentType = "text/event-stream";
context.Response.Write("data:test" );//須要使用data: 前綴
context.Response.Write("\n\n");//必需要以 空行結尾
}
Web Sockets:
socket 狀態:
WebSocket.OPENING(0)
WebSocket.OPEN(1)
WebSocket.CLOSING(2)
WebSocket.CLOSE(3)
var socket = new WebSocket("http://www.xx.com");
socket.onopen = function () {
}
socket.onerror = function () {
}
socket.onclose = function (event) {
console.log(event.wasClean);
console.log(event.code);
console.log(event.reason);
}
socket.send("haha");
socket.close();
********************* Chapter 22 高級技巧 *********************
高級函數:
安全的類型檢測:
function isArray(val) {
return Object.prototype.toString.call(val) == '[object Array]';
}
做用域安全的構造函數:
function Person(name, age) {
if (this instanceof Person) {
//這裏檢測了this , 也就是若是沒有 使用 new 關鍵字,也不會綁定到window 對象上
this.name = name;
this.age = age;
} else {
return new Person(name, age);
}
}
//沒有使用 new
var p = Person("test", 20);
console.log(p.name);
//繼承的實現
function Person(name, age) {
if (this instanceof Person) {
//這裏檢測了this , 也就是若是沒有 使用 new 關鍵字,也不會綁定到window 對象上
this.name = name;
this.age = age;
} else {
return new Person(name, age);
}
}
function Man(name, age) {
Person.call(this, name, age);
this.gender = 1;
}
//this instanceof Person == true
Man.prototype = new Person();//這樣子使用以後 ,this 就能夠是Person
var m = new Man('man', 30);
console.log(m.name);
惰性載入函數:
function createXHR() {
if (typeof XMLHttpRequest != 'undefined') {
createXHR = function () {
return new XMLHttpRequest();
}
} else if (typeof ActiveXObject != 'undefined') {
createXHR = function () {
var versions = ["MSXML2.XMLHttp6.0", "MSXML2.XMLHttp.3.0", "MSXML2.XMLHttp"];
for (var i = 0, len = versions.length; i < len; i++) {
try {
new ActiveXObject(versions[i]);
arguments.callee.activeString = versions[i];
break;
} catch (e) {
//next
}
}
return new ActiveXObject(arguments.callee.activeString);
}
} else {
createXHR = function () {
throw new Error("No XHR...");
}
}
}
函數綁定:
var handler = {
mesasge: "hello handler",
handlerClick: function () {
alert(this.mesasge);
}
};
var btn = document.getElementById("btn");
//btn.addEventListener("click", handler.handlerClick);//undefined
//自定義bind() 函數綁定方法,指定 this
btn.addEventListener("click", bind(handler.handlerClick, handler));//hello handler
//ES5 原生bind() 方法
//btn.addEventListener("click", handler.handlerClick.bind(handler));//hello handler
function bind(fn,context) {
return function () {
fn.apply(context, arguments);
}
}
函數柯里化:
function curry(fn) {
var args = Array.prototype.slice.call(arguments, 1);
return function () {
console.log(Array.isArray(arguments));//false
var innerArgs = Array.prototype.slice.call(arguments);// arguments 類型變爲 Array
console.log(Array.isArray(innerArgs));//true
var finnalArgs = args.concat(innerArgs);
return fn.apply(null, finnalArgs);
};
}
function add(num1, num2) {
return num1 + num2;
}
var curAdd = curry(add,10);
var res = curAdd(3);
console.log(res);//13
//柯里化與bind的使用
function bind(fn, context) {
var args = Array.prototype.slice.call(arguments, 2);
return function () {
var innerArgs = Array.prototype.slice.call(arguments);
var finArgs = args.concat(innerArgs);
return fn.apply(context, finArgs);
};
}
var handler = {
mesasge: "hello handler",
handlerClick: function (name,event) {
alert(this.mesasge + ", Name: " + name);
}
};
var btn = document.getElementById("btn");
btn.addEventListener("click", bind(handler.handlerClick, handler, 'btn'));//
//ES5
btn.addEventListener("click", handler.handlerClick.bind(handler,"btn");//
防篡改對象:
不可擴展對象:
var person = { 'name': "jk" };
console.log(Object.isExtensible(person));//true
//禁止擴展對象
Object.preventExtensions(person);
console.log(Object.isExtensible(person));//false
person.age = 19;
console.log(person.age);//undefined
密封的對象:
Object.seal(person);
delete person.name;
console.log(person.name);//jk
console.log(Object.isSealed(person));//true
console.log(Object.isExtensible(person));//false
凍結的對象:
Object.freeze(person);//不可擴展,密封的,writable =false
Object.isFrozen(person);
高級定時器:
重複的定時器:
var div = document.getElementById("div");
setTimeout(function () {
var left = parseInt(div.style.left) + 5;
console.log(left);
div.style.left = left + "px";
if (left < 500) {
//重複性
setTimeout(arguments.callee, 25);
}
}, 25)
Yielding Processes:
function trunk(arr,process,context) {
setTimeout(function () {
var item = arr.shift();
process.call(context, item);
if (arr.length > 0) {
setTimeout(arguments.callee, 100);
}
}, 100);
}
函數節流:
function throttle(method,context) {
clearTimeout(method.tId);
method.tId = setTimeout(function () {
method.call(context);
}, 100);
}
function resizeDiv() {
var div = document.getElementById("div");
div.style.height = div.offsetWidth + "px";
}
window.onresize = function () {
throttle(resizeDiv);
}
自定義事件:
function EventTarget() {
this.handlers = {};
}
EventTarget.prototype = {
constructor: EventTarget,
addHandler: function (type, handler) {
if (typeof this.handlers[type] == "undefined") {
this.handlers[type] = [];
}
this.handlers[type].push(handler);
},
fire: function (event) {
if (!event.target) {
event.target = this;
}
if (this.handlers[event.type] instanceof Array) {
var handlers = this.handlers[event.type];
for (var i = 0; i < handlers.length; i++) {
handlers[i](event);
}
}
},
removeHandler: function (type,handler) {
if (this.handlers[type] instanceof Array) {
var handlers = this.handlers[type];
for (var i = 0; i < handlers.length; i++) {
if (handlers[i] == handler) {
break;
}
}
}
handlers.splice(i, 1);
}
}
//Demo
function handleMsg(event) {
console.log("Msg:" + event.message);
}
var target = new EventTarget();
target.addHandler("message", handleMsg);
target.fire({type:"message",message:"this is test!"});
target.removeHandler("message", handleMsg);
target.fire({ type: "message", message: "this is test!" });
拖放:
var dargDrop = function () {
var dragging = null;
function handleEvent(event) {
var target = event.srcElement;
switch (event.type) {
case "mousedown":
if (target.className.indexOf("draggable") > -1) {
dragging = target;
}
break;
case "mousemove":
if (dragging != null) {
dragging.style.left = event.clientX + "px";
dragging.style.top = event.clientY + "px";
}
break;
case "mouseup":
dragging == null;
break;
}
}
return {
enable: function () {
document.addEventListener("mousedown", handleEvent);
document.addEventListener("mousemove", handleEvent);
document.addEventListener("mouseup", handleEvent);
},
disable: function () {
document.removeEventListener("mousedown", handleEvent);
document.removeEventListener("mousemove", handleEvent);
document.removeEventListener("mouseup", handleEvent);
}
};
}();
dargDrop.enable();
********************* Chapter 23 離線應用與客戶端存儲 *********************
離線檢測:
navigator.onLine;//狀態
window.ononline = function () {
}
window.onoffline = function () {
}
應用緩存:
緩存文件關聯:
<html manifest="/offline.manifest">
applicationCache的status:
0:無緩存
1:閒置
2:檢查中
3:下載中
4:更新完成
5:廢棄
applicationCache.update();
數據存儲:
Cookie:
IE用戶數據:
Web存儲機制:
Storage:
sessionStorage:
瀏覽器關閉後消失
for (var i = 0; i < sessionStorage.length; i++) {
var key = sessionStorage.key(i);
var val = sessionStorage.getItem(key);
}
for (var key in sessionStorage) {
var val = sessionStorage.getItem(key);
}
localStorage:
localStorage.name = 'test';
console.log(localStorage.getItem('name'));
localStorage.removeItem('name');
storage事件:
event屬性:
domain
key
newValue
oldValue
********************* Chapter 24 最佳實踐 *********************
可維護性:
什麼是可維護的代碼
代碼約定
鬆散耦合
編程實踐
尊重對象的全部權:
不要爲實例或原型添加屬性
不要爲實例或原型添加方法
不要重定義已存在的方法
避免全局量
命名空間的使用方式:
var MyTool = {}
MyTool.EventUtil={}
MyTool.CookieUtil={}
避免與null進行比較:
使用常量:
重複值
用戶界面字符串
URLs
任意可能會更改的值
性能:
注意做用域:
避免全局查找
避免with語句
選擇正確的方法:
避免沒必要要的屬性查找
減小算法複雜度
O(1)
O(n)
優化循環
減值迭代:從最大值開始到0的循環
簡化終止條件:
簡化循環體:
使用後測試循環:do-while
展開循環:
避免雙重解釋:
eval()或者Function構造函數或者setTimeout()傳入字符串
性能的其餘注意事項:
原生方法較快
Switch語句較快
位運算符較快
最小化語句數:
多個變量聲明:
var i=0,name="jk",arr=[]
插入迭代值:
var val = values[i];
i++;
優化:
var val= values[i++];
使用數組和對象字面量:
var person={};
var arr=[1,2,3];
優化DOM交互:
最小化現場更新:
var list = document.getElementById("myList"),
fragement = document.createDocumentFragment(),
item, i;
for (i = 0; i < 10; i++) {
item = document.createElement("li");
fragement.appendChild(item);
item.appendChild(document.createTextNode("Item" + i));
}
list.appendChild(fragement);
使用innerHTML
使用事件代理
使用的是事件冒泡的原理
注意HTMLCollection:
var imgs = document.getElementsByTagName("img"),img;
for (var i = 0, len = imgs.length; i < len; i++) {
img = imgs[i];
//處理
}
部署:
構建過程:
知識產權問題
文件大小
代碼組織
Ant構建工具
驗證:
JSLint
壓縮:
文件壓縮:
刪除額外的空白
刪除全部註釋
縮短變量名
HTTP壓縮:
********************* Chapter 25 新興的API *********************