******************************* Chapter 11 DOM扩展 *******************************
主要的扩展是 选择符API 和 HTML5
选择符API:
document.querySelector('.img');
document.querySelector('#test');
document.querySelectorAll('a');
//这个方式浏览器支持很少,返回是否可以查询得到的结果
document.matchesSelector('a.test');//true/false
元素遍历:
//这种方式就不会考虑后台元素的 空白文本节点了,
//因为使用 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="#" οnclick="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 文档模式版本号 5、6、7、8、9、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
IE9、Firefox、Chrome、Safari 事件一直冒泡到 window 对象
事件捕获:
因为老版本浏览器不支持,所以很少使用事件捕获,建议都使用事件冒泡
DOM事件流:
捕获阶段-->处于目标阶段-->冒泡阶段
事件处理程序:
HTML事件处理程序:
<!--<input type="button" name="name" value="btn" οnclick="alert(this.value)" />-->
<!--动态扩展性-->
<input type="button" name="name" value="btn" οnclick="alert(value)" />
<!--表单的扩展性-->
<form action="/" method="post">
<input type="text" name="userName" value="admin" />
<input type="button" name="name" value="btnGo" οnclick="alert(userName.value)" />
</form>
<!--普通方式-->
<!--<input type="button" name="name" value="btn" οnclick="show(this)" />-->
<!--这种是保险的方式,防止方法还没加载处理,就执行了点击事件,也是缺点之一 -->
<input type="button" name="name" value="btn" οnclick="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.οnclick=function(){
// event.stopPropagation();
// }
menu.addEventListener('click',function(){
event.stopPropagation();
},false)
document.οnclick=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 οnclick="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 *********************