<input type="button" value="Click Me" onclick="try{showMessage();}catch(ex){}">
使用try catch捕获错误
try {
var dd = document.getElemedntById('dd')
} catch (ex) {
alert(123)
}
addEventListener(),最后这个布尔值参数如果是true,表示在捕获阶段调用事件处理程序;如果是false,表示在冒泡阶段调用事件处理程
try {
btn.addEventListener('click', function() {
alert(this.id)
}, false)
} catch (ex) {
btn.attachEvent('onclick', function() {
alert(123)
})
}
removeEventListener(),要使用命名函数才能移除
btnfn = function() {
alert(this.id)
}
btn.addEventListener('click', btnfn, false)
btn.removeEventListener('click',btnfn,false)
attachEvent()与detachEvent(),1、this作用域为window; 2、执行顺序由后往前;
btn.attachEvent('onclick',function(){
alert(this) //特别注意,这里是window
})
btn.attachEvent("onclick", function(){
alert("Clicked"); //弹2
});
btn.attachEvent("onclick", function(){
alert("Hello world!"); //弹1
});
兼容方法:
var EventUtil = {
addHandler: function(element, type, handler) {
if (element.addEventListener) {
element.addEventListener(type, handler, false);
} else if (element.attachEvent) {
element.attachEvent("on" + type, handler);
} else {
element["on" + type] = handler;
}
},
removeHandler: function(element, type, handler) {
if (element.removeEventListener) {
element.removeEventListener(type, handler, false);
} else if (element.detachEvent) {
element.detachEvent("on" + type, handler);
} else {
element["on" + type] = null;
}
}
};
var handler = function() {
alert('abc')
}
EventUtil.addHandler(btn, 'click', handler)
EventUtil.removeHandler(btn, "click", handler);
事件对象

对象this 始终等于currentTarget 的值,而target 则只包含事件的实
际目标。如果直接将事件处理程序指定给了目标元素,则this、currentTarget 和target 包含相同
的值。来看下面的例子。
btn.onclick = function(event){
alert(event.currentTarget === this)
alert(event.target === this)
}
document.body.onclick = function(event) {
alert(event.currentTarget == document.body) //true
alert(this === document.body) //true
alert(event.target == document.getElementById('mybtn')) //true
}
使用event.type判断不同事件;
var handler = function(event) {
switch (event.type) {
case 'click':
alert('clicked')
break;
case 'mouseover':
alert('mouseovered')
break;
case 'mouseout':
alert('mouseouted');
break;
}
}
btn.onclick = handler;
btn.onmouseover = handler;
btn.onmouseout = handler;
btn.onclick = function(event) {
alert('clicked')
event.stopPropagation()
}
document.body.onclick = function(event) {
alert('body clicked')
}
IE下的事件;

所以不能认为this 会始终等于事件目标。故而,最好还是使用event.srcElement 比较保
var btn = document.getElementById("myBtn");
btn.onclick = function(){
alert(window.event.srcElement === this); //true
};
btn.attachEvent("onclick", function(event){
alert(event.srcElement === this); //false
});
cancelBubble 属性与DOM 中的stopPropagation()方法作用相同,都是用来停止事
件冒泡的。由于IE 不支持事件捕获,因而只能取消事件冒泡;但stopPropagatioin()可以同时取消
事件捕获和冒泡
所以综合起来的跨浏览器事件代码为:
var EventUtil = {
addHandler: function(element, type, handler) {
if (element.addEventListener) {
element.addEventListener(type, handler, false);
} else if (element.attachEvent) {
element.attachEvent("on" + type, handler);
} else {
element["on" + type] = handler;
}
},
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;
}
},
removeHandler: function(element, type, handler) {
if (element.removeEventListener) {
element.removeEventListener(type, handler, false);
} else if (element.detachEvent) {
element.detachEvent("on" + type, handler);
} else {
element["on" + type] = null;
}
},
stopPropagation: function(event) {
if (event.stopPropagation) {
event.stopPropagation();
} else {
event.cancelBubble = true;
}
}
};
//使用
btn.onclick = function(event) {
event = EventUtil.getEvent(event);
};
btn.onclick = function(event) {
event = EventUtil.getEvent(event);
var target = EventUtil.getTarget(event);
};
var link = document.getElementById("myLink");
link.onclick = function(event) {
event = EventUtil.getEvent(event);
EventUtil.preventDefault(event);
};
var btn = document.getElementById("myBtn");
btn.onclick = function(event) {
alert("Clicked");
event = EventUtil.getEvent(event);
EventUtil.stopPropagation(event);
};
document.body.onclick = function(event) {
alert("Body clicked");
};
图片加载完后显示弹出
var image = document.getElementById('myimage')
EventUtil.addHandler(image,'load',function(event){
event = EventUtil.getEvent(event);
alert(EventUtil.getTarget(event).src);
})
EventUtil.addHandler(window,'load',function(){
var image = new Image();
EventUtil.addHandler(image,'load',function(event){
alert('Image Loaded')
})
image.src = 'smail.gif'
})
script外部地址加载完成
EventUtil.addHandler(window,'load',function(){
var _srcipt = document.createElement('script')
EventUtil.addHandler(_srcipt,'load',function(event){
alert('loaded')
})
_srcipt.src = 'http://ajax.googleapis.com/ajax/libs/jquery/1.2.6/jquery.min.js'
document.body.appendChild(_srcipt)
})
css外部检测,低版本chrome/firefox可能不支持,未验证
EventUtil.addHandler(window, 'load', function() {
var _css = document.createElement('link')
_css.type = 'text/css'
_css.rel = 'stylesheet'
EventUtil.addHandler(_css, 'load', function(event) {
alert('loaded')
})
_css.href = 'https://assets-cdn.github.com/assets/frameworks-827a4e004aa05724993ea7616e4af53894825443811a270e2b9bce76e3453f19.css'
document.body.appendChild(_srcipt)
})
resize事件,推荐写法
EventUtil.addHandler(window, "resize", function(event) {
alert("Resized");
});
EventUtil.addHandler(window, "scroll", function(event) {
if (document.compatMode == "CSS1Compat") {
alert(document.documentElement.scrollTop);
} else {
alert(document.body.scrollTop);
}
});
焦点事件会在页面元素获得或失去焦点时触发。利用这些事件并与document.hasFocus()方法及
document.activeElement 属性配合,可以知晓用户在页面上的行踪。有以下6 个焦点事件。
blur:在元素失去焦点时触发。这个事件不会冒泡;所有浏览器都支持它。
DOMFocusIn:在元素获得焦点时触发。这个事件与HTML 事件focus 等价,但它冒泡。只有
Opera 支持这个事件。DOM3 级事件废弃了DOMFocusIn,选择了focusin。
DOMFocusOut:在元素失去焦点时触发。这个事件是HTML 事件blur 的通用版本。只有Opera
支持这个事件。DOM3 级事件废弃了DOMFocusOut,选择了focusout。
focus:在元素获得焦点时触发。这个事件不会冒泡;所有浏览器都支持它。
focusin:在元素获得焦点时触发。这个事件与HTML 事件focus 等价,但它冒泡。支持这个
事件的浏览器有IE5.5+、Safari 5.1+、Opera 11.5+和Chrome。
focusout:在元素失去焦点时触发。这个事件是HTML 事件blur 的通用版本。支持这个事件
的浏览器有IE5.5+、Safari 5.1+、Opera 11.5+和Chrome。
当焦点从页面中的一个元素移动到另一个元素,会依次触发下列事件:
(1) focusout 在失去焦点的元素上触发;
(2) focusin 在获得焦点的元素上触发;
(3) blur 在失去焦点的元素上触发;
(4) DOMFocusOut 在失去焦点的元素上触发;
(5) focus 在获得焦点的元素上触发;
(6) DOMFocusIn 在获得焦点的元素上触发。
事件都不冒泡
var _mybtn = document.getElementById('mybtn')
EventUtil.addHandler(_mybtn, 'focus', function() { //获得
alert(1)
})
EventUtil.addHandler(_mybtn, 'blur', function() {//失去
alert(2)
})
EventUtil.addHandler(_mybtn, 'focusin', function() {//获得
alert(1)
})
EventUtil.addHandler(_mybtn, 'focusout', function() {//失去
alert(2)
})
鼠标与滚轮事件
click/dblclick/mouseenter/mouseleave/mousemove/mouseout/mouseover/mouseup/
执行顺序:
(1) mousedown
(2) mouseup
(3) click
(4) mouseup
(5) dblclick
可以使用类似下列代码取得鼠标事件的客户端坐标信息:
var div = document.getElementById("myDiv");
EventUtil.addHandler(div, "click", function(event){
event = EventUtil.getEvent(event);
alert("Client coordinates: " + event.clientX + "," + event.clientY);
});
var div = document.getElementById("myDiv");
EventUtil.addHandler(div, "click", function(event){
event = EventUtil.getEvent(event);
alert("Page coordinates: " + event.pageX + "," + event.pageY);
});
在页面没有滚动的情况下,pageX 和pageY 的值与clientX 和clientY 的值相等。
滚动情况下:page 一定大于 client
EventUtil.addHandler(document.body, "click", function(event) {
event = EventUtil.getEvent(event);
console.log("Page coordinates: " + event.pageX + "," + event.pageY);
});
EventUtil.addHandler(document.body, "click", function(event) {
event = EventUtil.getEvent(event);
console.log("client coordinates: " + event.clientX + "," + event.clientY);
});
IE8不支持page,所以可用client + scroll 相加计算出
var div = document.getElementById("myDiv");
EventUtil.addHandler(div, "click", function(event) {
event = EventUtil.getEvent(event);
var pageX = event.pageX,
pageY = event.pageY;
if (pageX === undefined) {
pageX = event.clientX + (document.body.scrollLeft ||
document.documentElement.scrollLeft);
}
if (pageY === undefined) {
pageY = event.clientY + (document.body.scrollTop ||
document.documentElement.scrollTop);
}
alert("Page coordinates: " + pageX + "," + pageY);
});
鼠标相对于整个屏幕坐标位置,screenX 和 screenY
var div = document.getElementById("myDiv");
EventUtil.addHandler(div, "click", function(event){
event = EventUtil.getEvent(event);
alert("Screen coordinates: " + event.screenX + "," + event.screenY);
});
虽然鼠标事件主要是使用鼠标来触发的,但在按下鼠标时键盘上的某些键的状态也可以影响到所要
采取的操作。这些修改键就是Shift、Ctrl、Alt 和Meta(在Windows 键盘中是Windows 键,在苹果机中
是Cmd 键),它们经常被用来修改鼠标事件的行为。DOM 为此规定了4 个属性,表示这些修改键的状
态:shiftKey、ctrlKey、altKey 和metaKey。这些属性中包含的都是布尔值,如果相应的键被按
下了,则值为true,否则值为false。当某个鼠标事件发生时,通过检测这几个属性就可以确定用户
是否同时按下了其中的键。来看下面的
var div = document.getElementById("myDiv");
EventUtil.addHandler(div, "click", function(event) {
event = EventUtil.getEvent(event);
var keys = new Array();
if (event.shiftKey) {
keys.push("shift");
}
if (event.ctrlKey) {
keys.push("ctrl");
}
if (event.altKey) {
keys.push("alt");
}
if (event.metaKey) {
keys.push("meta");
}
alert("Keys: " + keys.join(","));
});
DOM通过event 对象的relatedTarget 属性提供了相关元素的信
只对于mouseover和mouseout 事件才包含值,其它值是null
IE8及之前版本不支持relatedTarget
mouseover -->IE 的fromElement
mouseout --》IE 的toElement
继续完善
var EventUtil = {
addHandler: function(element, type, handler) {
if (element.addEventListener) {
element.addEventListener(type, handler, false);
} else if (element.attachEvent) {
element.attachEvent("on" + type, handler);
} else {
element["on" + type] = handler;
}
},
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;
}
},
removeHandler: function(element, type, handler) {
if (element.removeEventListener) {
element.removeEventListener(type, handler, false);
} else if (element.detachEvent) {
element.detachEvent("on" + type, handler);
} else {
element["on" + type] = null;
}
},
stopPropagation: function(event) {
if (event.stopPropagation) {
event.stopPropagation();
} else {
event.cancelBubble = true;
}
},
getRelatedTarget: function(event) {
if (event.relatedTarget) {
return event.relatedTarget;
} else if (event.toElement) {
return event.toElement;
} else if (event.fromElement) {
return event.fromElement;
} else {
return null;
}
}
};
var div = document.getElementById("myDiv");
EventUtil.addHandler(div, "mouseout", function(event) {
event = EventUtil.getEvent(event);
var target = EventUtil.getTarget(event);
var relatedTarget = EventUtil.getRelatedTarget(event);
alert("Moused out of " + target.tagName + " to " + relatedTarget.tagName);
//Moused out of DIV to BODY
鼠标按钮
DOM的button 属性可能有如下3 个值:0 表示主鼠标按钮,1 表示中间的鼠
标按钮(鼠标滚轮按钮),2 表示次鼠标按钮。在常规的设置中,主鼠标按钮就是鼠标左键,而次鼠标
按钮就是鼠标右
最常见的做法就是将IE 模型规范化为DOM 方式
添加getButton
var EventUtil = {
addHandler: function(element, type, handler) {
if (element.addEventListener) {
element.addEventListener(type, handler, false);
} else if (element.attachEvent) {
element.attachEvent("on" + type, handler);
} else {
element["on" + type] = handler;
}
},
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;
}
},
removeHandler: function(element, type, handler) {
if (element.removeEventListener) {
element.removeEventListener(type, handler, false);
} else if (element.detachEvent) {
element.detachEvent("on" + type, handler);
} else {
element["on" + type] = null;
}
},
stopPropagation: function(event) {
if (event.stopPropagation) {
event.stopPropagation();
} else {
event.cancelBubble = true;
}
},
getRelatedTarget: function(event) {
if (event.relatedTarget) {
return event.relatedTarget;
} else if (event.toElement) {
return event.toElement;
} else if (event.fromElement) {
return event.fromElement;
} else {
return null;
}
},
getButton: function(event) {
if (document.implementation.hasFeature("MouseEvents", "2.0")) {
return event.button;
} else {
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;
}
}
}
};
var div = document.getElementById("myDiv");
EventUtil.addHandler(div, "mousedown", function(event) {
event = EventUtil.getEvent(event);
alert(EventUtil.getButton(event)); //左0 中1 右2
});
鼠标滚轮:
mousewheel 事件时显示wheelDelta 的值,
ff:支持:DOMMouseScroll
EventUtil.addHandler(document, "mousewheel", function(event){
event = EventUtil.getEvent(event);
console.log(event.wheelDelta); //上120,下-120
});
//ff
EventUtil.addHandler(window, "DOMMouseScroll", function(event) {
event = EventUtil.getEvent(event); // 上-3 下3
alert(event.detail);
});
整合添加:
var EventUtil = {
addHandler: function(element, type, handler) {
if (element.addEventListener) {
element.addEventListener(type, handler, false);
} else if (element.attachEvent) {
element.attachEvent("on" + type, handler);
} else {
element["on" + type] = handler;
}
},
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;
}
},
removeHandler: function(element, type, handler) {
if (element.removeEventListener) {
element.removeEventListener(type, handler, false);
} else if (element.detachEvent) {
element.detachEvent("on" + type, handler);
} else {
element["on" + type] = null;
}
},
stopPropagation: function(event) {
if (event.stopPropagation) {
event.stopPropagation();
} else {
event.cancelBubble = true;
}
},
getRelatedTarget: function(event) {
if (event.relatedTarget) {
return event.relatedTarget;
} else if (event.toElement) {
return event.toElement;
} else if (event.fromElement) {
return event.fromElement;
} else {
return null;
}
},
getButton: function(event) {
if (document.implementation.hasFeature("MouseEvents", "2.0")) {
return event.button;
} else {
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;
}
}
},
getWheelDelta: function(event) {
if (event.wheelDelta) {
return (event.wheelDelta);
} else {
return -event.detail * 40;
}
}
}
//使用
//handleMouseWheel()函数可以用作两个事件的处理程序(如果指定的事件不存在,则为该事件指定处
理程序的代码就会静默地失败)
function handleMouseWheel(event){
event = EventUtil.getEvent(event);
var delta = EventUtil.getWheelDelta(event);
alert(delta); //下-120,上120
}
EventUtil.addHandler(document, "mousewheel", handleMouseWheel);
EventUtil.addHandler(document, "DOMMouseScroll", handleMouseWheel);
键盘与文本
键盘事件:
keydown当用户按下键盘上的任意键时触发,而且如果按住不放的话,会重复触发此事件
keypress:当用户按下键盘上的字符键时触发,而且如果按住不放的话,会重复触发此事件。
按下Esc 键也会触发这个事件。Safari 3.1 之前的版本也会在用户按下非字符键时触发keypress
事件。
keyup:当用户释放键盘上的键时触发。
文本事件:textInput,对keypress补充
按下字符:keydown--》keypress【前两个是文本变化之前】--》keyup
连续按:连接触发:keydown--》keypress
按下非字符:keydown --》keyup
也有shiftKey、ctrlKey、altKey 和metaKey[非IE] 属性
键码
在发生keydown 和keyup 事件时,event 对象的keyCode 属性中会包含一个代码
var textbox = document.getElementById("myText");
EventUtil.addHandler(textbox, "keyup", function(event) {
event = EventUtil.getEvent(event);
alert(event.keyCode); //显示keyCode值
});
var EventUtil = {
addHandler: function(element, type, handler) {
if (element.addEventListener) {
element.addEventListener(type, handler, false);
} else if (element.attachEvent) {
element.attachEvent("on" + type, handler);
} else {
element["on" + type] = handler;
}
},
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;
}
},
removeHandler: function(element, type, handler) {
if (element.removeEventListener) {
element.removeEventListener(type, handler, false);
} else if (element.detachEvent) {
element.detachEvent("on" + type, handler);
} else {
element["on" + type] = null;
}
},
stopPropagation: function(event) {
if (event.stopPropagation) {
event.stopPropagation();
} else {
event.cancelBubble = true;
}
},
getRelatedTarget: function(event) {
if (event.relatedTarget) {
return event.relatedTarget;
} else if (event.toElement) {
return event.toElement;
} else if (event.fromElement) {
return event.fromElement;
} else {
return null;
}
},
getButton: function(event) {
if (document.implementation.hasFeature("MouseEvents", "2.0")) {
return event.button;
} else {
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;
}
}
},
getWheelDelta: function(event) {
if (event.wheelDelta) {
return (event.wheelDelta);
} else {
return -event.detail * 40;
}
},
getCharCode: function(event) {
if (typeof event.charCode == "number") {
return event.charCode;
} else {
return event.keyCode;
}
}
}
var textbox = document.getElementById("myText");
EventUtil.addHandler(textbox, "keypress", function(event) {
event = EventUtil.getEvent(event);
alert(EventUtil.getCharCode(event));//值出字符编码
});
之后可以使用String.fromCharCode(number),再转为正常字符;
所有非字符

特殊情况: ff o 分号键keyCode = 59 【ASCII分号编码】; ie safari分号键 = 186;【按键编码】
由于存在跨浏览器问题,因此本书不推荐使用key、keyIdentifier 或char。
textInput事件
替代keypress 的textInput 事件的行为稍有不同。
区别一:就是任何可以获得焦点的元素都可以触发keypress 事件,但只有可编辑区域才能触发textInput事件。
区别二:textInput 事件只会在用户按下能够输入实际字符的键时才会被触发,
而keypress事件则在按下那些能够影响文本显示的键时也会触发(例如退格键)。
由于textInput 事件主要考虑的是字符,因此它的event 对象中还包含一个data 属性,这个属
性的值就是用户输入的字符(而非字符编码)。换句话说,用户在没有按上档键的情况下按下了S 键,
data 的值就是"s",而如果在按住上档键时按下该键,data 的值就是"S"。
var textbox = document.getElementById("myText");
EventUtil.addHandler(textbox, "textInput", function(event){
event = EventUtil.getEvent(event);
alert(event.data); //按下什么输出什么
});
HTML5事件
- contextmenu 事件显示菜单,支持contextmenu 事件的浏览器有IE、Firefox、Safari、Chrome 和Opera 11+。
EventUtil.addHandler(window, "load", function(event) {
var div = document.getElementById("myDiv");
EventUtil.addHandler(div, "contextmenu", function(event) {
event = EventUtil.getEvent(event);
EventUtil.preventDefault(event);
var menu = document.getElementById("myMenu");
menu.style.left = event.clientX + "px";
menu.style.top = event.clientY + "px";
menu.style.visibility = "visible";
});
EventUtil.addHandler(document, "click", function(event) {
document.getElementById("myMenu").style.visibility = "hidden";
});
});
- beforeunload 事件,是为了让开发人员有可能在页面卸载前阻止这一操作,为了显示这个弹出对话框,必须将event.returnValue 的值设置为要显示给用户的字符串(对IE 及Fiefox 而言),同时作为函数的值返回
[
returnValue Boolean 读/写 默认值为true,但将其设置为false就可以取消事件的默认行为(与
DOM中的preventDefault()方法的作用相同)
]
EventUtil.addHandler(window, "beforeunload", function(event) {
event = EventUtil.getEvent(event);
var message = "I'm really going to miss you if you go.";
event.returnValue = message;
return message;
});
- DOMContentLoaded 事件 DOM加载完成后触发;
要处理DOMContentLoaded 事件,可以为document 或window 添加相应的事件处理程序(尽管
这个事件会冒泡到window,但它的目标实际上是document)。来看下面的例子。
注:这个事件始终都会在load 事件之前触发
EventUtil.addHandler(document, "DOMContentLoaded", function(event){
alert("Content loaded");
});
不支持的浏览器使用:
setTimeout(function(){
//在此添加事件处理程序
}, 0);
- readystatechange 事件
支持readystatechange 事件的每个对象都有一个readyState 属性
uninitialized(未初始化):对象存在但尚未初始化。
loading(正在加载):对象正在加载数据。
loaded(加载完毕):对象加载数据完成。
interactive(交互):可以操作对象了,但还没有完全加载。
complete(完成):对象已经加载完毕。
不支持则会跳过,所以一般readystatechange事件经常会少于4次;而readyState则总是不连续;
EventUtil.addHandler(document, "readystatechange", function(event) {
if (document.readyState == "interactive") {
alert("Content loaded");
}
});
同时检测交互和完成阶
EventUtil.addHandler(document, "readystatechange", function(event) {
if (document.readyState == "interactive" || document.readyState == "complete") {
EventUtil.removeHandler(document, "readystatechange", arguments.callee);
alert("Content loaded");
}
});
对于上面的代码来说,当readystatechange 事件触发时,会检测document.readyState 的值,
看当前是否已经进入交互阶段或完成阶段。如果是,则移除相应的事件处理程序以免在其他阶段再执行。
注意,由于事件处理程序使用的是匿名函数,因此这里使用了arguments.callee 来引用该函数。然
后,会显示一个警告框,说明内容已经加载完毕。这样编写代码可以达到与使用DOMContentLoaded
十分相近的效
下面展示了一段加载外部JavaScript/css 文件的代码
//js
EventUtil.addHandler(window, "load", function() {
var script = document.createElement("script");
EventUtil.addHandler(script, "readystatechange", function(event) {
event = EventUtil.getEvent(event);
var target = EventUtil.getTarget(event);
if (target.readyState == "loaded" || target.readyState == "complete") {
EventUtil.removeHandler(target, "readystatechange", arguments.callee);
alert("Script Loaded");
}
});
script.src = "example.js";
document.body.appendChild(script);
});
//css
EventUtil.addHandler(window, "load", function() {
var link = document.createElement("link");
link.type = "text/css";
link.rel = "stylesheet";
EventUtil.addHandler(script, "readystatechange", function(event) {
event = EventUtil.getEvent(event);
var target = EventUtil.getTarget(event);
if (target.readyState == "loaded" || target.readyState == "complete") {
EventUtil.removeHandler(target, "readystatechange", arguments.callee);
alert("CSS Loaded");
}
});
link.href = "example.css";
document.getElementsByTagName("head")[0].appendChild(link);
});
- pageshow 和pagehide 事件
(略)
- hashchange 事件
必须要把hashchange 事件处理程序添加给window 对象,然后URL 参数列表只要变化就会调用
它。此时的event 对象应该额外包含两个属性:oldURL 和newURL。这两个属性分别保存着参数列表
变化前后的完整URL。例如:
EventUtil.addHandler(window, "hashchange", function(event){
alert("Old URL: " + event.oldURL + "\nNew URL: " + event.newURL);
}); //前后变化,完整url
EventUtil.addHandler(window, "hashchange", function(event){
alert("Current hash: " + location.hash);
});//当前 #后字符
检测是否支持
var isSupported = ("onhashchange" in window) && (document.documentMode ===
undefined || document.documentMode > 7);
13.4.8 设备事件
- orientationchange 事件

苹果公司为移动Safari 中添加了orientationchange 事件,以便开发人员能够确定用户何时将设
备由横向查看模式切换为纵向查看模式。移动Safari 的window.orientation 属性中可能包含3 个值:
0 表示肖像模式,90 表示向左旋转的横向模式(“主屏幕”按钮在右侧),-90 表示向右旋转的横向模
式(“主屏幕”按钮在左侧)。相关文档中还提到一个值,即180 表示iPhone 头朝下;但这种模式至今
尚未得到支持。图13-10 展示了window.orientation 的每个值的含义
只要用户改变了设备的查看模式,就会触发orientationchange 事件。此时的event 对象不包
含任何有价值的信息,因为唯一相关的信息可以通过window.orientation 访问到。下面是使用这个
事件的典型示例
EventUtil.addHandler(window, "load", function(event) {
var div = document.getElementById("myDiv");
div.innerHTML = "Current orientation is " + window.orientation;
//改变时触发
EventUtil.addHandler(window, "orientationchange", function(event) {
div.innerHTML = "Current orientation is " + window.orientation;
});
});
//横屏
window.orientation == 90 || window.orientation == -90
//竖屏
window.orientation == 0 || window.orientation == 180
//粗略检测,并不准,ie都返回false
alert(document.implementation.hasFeature("orientationchange", "2.0"))
- deviceorientation 事件
- 事件的意图是告诉开发人员设备在空间中朝向哪儿,而不是如何移动;
设备在三维空间中是靠x、y 和z 轴来定位的 三个值都是0
x轴: 左 --》 右;
y轴: 下 --》 上;
z轴: 后 --》 前;
事件对象包含以下5 个属性。
alpha:在围绕z 轴旋转时(即左右旋转时),y 轴的度数差;是一个介于0 到360 之间的浮点数。
beta:在围绕x 轴旋转时(即前后旋转时),z 轴的度数差;是一个介于180 到180 之间的浮点数。
gamma:在围绕y 轴旋转时(即扭转设备时),z 轴的度数差;是一个介于90 到90 之间的浮点数。
absolute:布尔值,表示设备是否返回一个绝对值。
compassCalibrated:布尔值,表示设备的指南针是否校准过。
13.4.9 触摸与手势事件
touchstart/touchmove/touchend/touchcancel
每個event對象都有以下常見屬性;
bubbles、cancelable、view、clientX、clientY、screenX、screenY、detail、altKey、shiftKey、ctrlKey 和metaKey。
touches:表示当前跟踪的触摸操作的Touch 对象的数组。
targetTouchs:特定于事件目标的Touch 对象的数组。
changeTouches:表示自上次触摸以来发生了什么改变的Touch 对象的数组。
每个Touch 对象包含下列属性。
clientX:触摸目标在视口中的x 坐标。
clientY:触摸目标在视口中的y 坐标。
identifier:标识触摸的唯一ID。
pageX:触摸目标在页面中的x 坐标。
pageY:触摸目标在页面中的y 坐标。
screenX:触摸目标在屏幕中的x 坐标。
screenY:触摸目标在屏幕中的y 坐标。
target:触摸的DOM 节点目标。
使用这些属性可以跟踪用户对屏幕的
function handleTouchEvent(event) {
if (event.touches.length == 1) {
var _output = document.getElementById('output')
switch (event.type) {
case 'touchstart':
_output.innerHTML = 'Touch started' + event.touches[0].clientX + ',' + event.touches[0].clientY
break;
case 'touchend':
_output.innerHTML += '<br> Touche ended' + event.changedTouches[0].clientX + ':' +
event.changedTouches[0].clientY + ';';
break;
case 'touchmove':
event.preventDefault();
_output.innerHTML += '<br> Touch move' +
event.changedTouches[0].clientX + ':' +
event.changedTouches[0].clientY + ';';
break;
}
}
}
EventUtil.addHandler(document, 'touchstart', handleTouchEvent)
EventUtil.addHandler(document, 'touchend', handleTouchEvent)
EventUtil.addHandler(document, 'touchmove', handleTouchEvent)
當touchstart發生: 觸摸信息輸出到
中 當touchmove發生:取消默認行為,阻止滾動,輸出變化信息
當touchend發生時:輸出有關觸摸操作信息,在touchend發生時:touches集合中就沒有任何信息,因為不存在活動觸摸操作,此時必須使用changeTouches集合
發生順序如下:
(1) touchstart
(2) mouseover
(3) mousemove(一次)
(4) mousedown
(5) mouseup
(6) click
(7) touchend
- 手势事件
當兩個手指觸摸時,就會產生手勢,手勢通常會改變顯示項大小,或旋轉顯示項,三個事件
gesturestart:当一个手指已经按在屏幕上而另一个手指又触摸屏幕时触发。
gesturechange:当触摸屏幕的任何一个手指的位置发生变化时触发。
gestureend:当任何一个手指从屏幕上面移开时触发。
当一个手指在屏幕时,触发touchstart
另一个手指放在屏幕,先触发gesturestart事件,随后触发该手指的touchstart
如果一个或两个手指在屏幕移动,触发gesturechange事件,但只要有一手指移开,触发gestureend事件,
最后再触发该手指的touchend事件;
每个event对象包含::
bubbles、cancelable、view、clientX、clientY、screenX、screenY、detail、altKey、shiftKey、
ctrlKey 和metaKey、还有两个额外属性:rotation、scale
rotation: 表示手指变化引起的旋转角度, -值逆时针,+ 顺时针(该值从0开始)
scale: 表示两个手指距离变化情况,如内收缩会缩短距离,从1开始;
function handleTouchEvent(event) {
var _output = document.getElementById('output')
switch (event.type) {
case 'gesturestart':
_output.innerHTML = 'Gesture started rotation = ' + event.rotation + ', scale' + event.scale;
break;
case 'gestureend':
_output.innerHTML += '<br> Gesture end rotation = ' + event.rotation + ', scale' + event.scale;
break;
case 'gesturechange':
event.preventDefault();
_output.innerHTML += '<br> Gesture change rotation = ' + event.rotation + ', scale' + event.scale;
break;
}
}
EventUtil.addHandler(document, 'gesturestart', handleTouchEvent)
EventUtil.addHandler(document, 'gestureend', handleTouchEvent)
EventUtil.addHandler(document, 'gesturechange', handleTouchEvent)
13.5.1 事件委托
var list = document.getElementById('myLinks')
EventUtil.addHandler(list, 'click', function(event) { //父级绑定click
event = EventUtil.getEvent(event)
var target = EventUtil.getTarget(event)
switch (target.id) { //检测目标元素属性
case 'doSomething':
document.title = 'i cahnge the document is ttile'
break;
case 'goSomewhere':
location.href = 'http://www.x.com';
break;
case 'sayHi':
alert('hi')
break;
}
})
var btn = document.getElementById('myBtn')
btn.onclick = function(){
document.getElementById('myDiv').innerHTML = 'processing' //按钮被替换了,但click事件还在
}
//所以
var btn = document.getElementById('myBtn')
btn.onclick = function(){
btn.onclick = null; //先移除
document.getElementById('myDiv').innerHTML = 'processing' //按钮被替换了,但click事件还在
}
13.6.1 DOM中的事件模拟
- 模拟鼠标事件
创建新的鼠标事件对象并为其指定必要的信息,就可以模拟鼠标事件。创建鼠标事件对象的方法是
为createEvent()传入字符串"MouseEvents"。返回的对象有一个名为initMouseEvent()方法,
用于指定与该鼠标事件有关的信息。这个方法接收15 个参数,分别与鼠标事件中每个典型的属性一一
对应;这些参数的含义如下。
对应;这些参数的含义如下。
type(字符串):表示要触发的事件类型,例如"click"。
bubbles(布尔值):表示事件是否应该冒泡。为精确地模拟鼠标事件,应该把这个参数设置为
true。
cancelable(布尔值):表示事件是否可以取消。为精确地模拟鼠标事件,应该把这个参数设
置为true。
view(AbstractView):与事件关联的视图。这个参数几乎总是要设置为document.defaultView。
detail(整数):与事件有关的详细信息。这个值一般只有事件处理程序使用,但通常都设置为0。
screenX(整数):事件相对于屏幕的X 坐标。
screenY(整数):事件相对于屏幕的Y 坐标。
clientX(整数):事件相对于视口的X 坐标。
clientY(整数):事件想对于视口的Y 坐标。
ctrlKey(布尔值):表示是否按下了Ctrl 键。默认值为false。
altKey(布尔值):表示是否按下了Alt 键。默认值为false。
shiftKey(布尔值):表示是否按下了Shift 键。默认值为false。
metaKey(布尔值):表示是否按下了Meta 键。默认值为false。
button(整数):表示按下了哪一个鼠标键。默认值为0。
relatedTarget(对象):表示与事件相关的对象。这个参数只在模拟mouseover 或mouseout
时使用。
var btn = document.getElementById('myBtn')
//创建事件对象
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)
- 模拟键盘事件
一、DOM3 级规定,调用createEvent()并传入"KeyboardEvent"就可以创建一个键盘事件。返回的
事件对象会包含一个initKeyEvent()方法,这个方法接收下列参数
type(字符串):表示要触发的事件类型,如"keydown"。
bubbles(布尔值):表示事件是否应该冒泡。为精确模拟鼠标事件,应该设置为true。
cancelable(布尔值):表示事件是否可以取消。为精确模拟鼠标事件,应该设置为true。
view (AbstractView ):与事件关联的视图。这个参数几乎总是要设置为document.
defaultView。
key(布尔值):表示按下的键的键码。
location(整数):表示按下了哪里的键。0 表示默认的主键盘,1 表示左,2 表示右,3 表示
数字键盘,4 表示移动设备(即虚拟键盘),5 表示手柄。
modifiers(字符串):空格分隔的修改键列表,如"Shift"。
repeat(整数):在一行中按了这个键多少次。
DOM3级不提倡使用keypress 事件,因此只能利用这种技术来模拟keydown 和keyup 事件。
var textbox = document.getElementById("myTextbox"),
event;
//以DOM3 级方式创建事件对象
if (document.implementation.hasFeature("KeyboardEvents", "3.0")) {
event = document.createEvent("KeyboardEvent");
//初始化事件对象
event.initKeyboardEvent("keydown", true, true, document.defaultView, "a", 0, "Shift", 0);
}
//触发事件
textbox.dispatchEvent(event);
这个例子模拟的是按住Shift 的同时又按下A 键。在使用document.createEvent
("KeyboardEvent")之前,应该先检测浏览器是否支持DOM3 级事件;其他浏览器返回一个非标准的
KeyboardEvent 对象。
二、在Firefox 中,调用createEvent()并传入"KeyEvents"就可以创建一个键盘事件。返回的事件
对象会包含一个initKeyEvent()方法,这个方法接受下列10 个参数。
type(字符串):表示要触发的事件类型,如"keydown"。
bubbles(布尔值):表示事件是否应该冒泡。为精确模拟鼠标事件,应该设置为true。
cancelable(布尔值):表示事件是否可以取消。为精确模拟鼠标事件,应该设置为true。
view(AbstractView):与事件关联的视图。这个参数几乎总是要设置为document.default-
View。
ctrlKey(布尔值):表示是否按下了Ctrl 键。默认值为false。
altKey(布尔值):表示是否按下了Alt 键。默认值为false。
shiftKey(布尔值):表示是否按下了Shift 键。默认值为false。
metaKey(布尔值):表示是否按下了Meta 键。默认值为false。
keyCode(整数):被按下或释放的键的键码。这个参数对keydown 和keyup 事件有用,默认
值为0。
charCode(整数):通过按键生成的字符的ASCII 编码。这个参数对keypress 事件有用,默
认值为0。
//只适用于Firefox
var textbox = document.getElementById("myTextbox")
//创建事件对象
var event = document.createEvent("KeyEvents");
//初始化事件对象
event.initKeyEvent("keypress", true, true, document.defaultView, false, false,
false, false, 65, 65);
//触发事件
textbox.dispatchEvent(event);
三、其它浏览器
首先创建了一个通用事件,然后调用initEvent()对其进行初始化,最后又为其添加了
键盘事件的具体信息。在此必须要使用通用事
var textbox = document.getElementById("myTextbox");
//创建事件对象
var event = document.createEvent("Events");
//初始化事件对象
event.initEvent(type, bubbles, cancelable);
event.view = document.defaultView;
event.altKey = false;
event.ctrlKey = false;
event.shiftKey = false;
event.metaKey = false;
event.keyCode = 65;
event.charCode = 65;
//触发事件
textbox.dispatchEvent(event);
- 模拟其他事件
模拟变动事件, 可以使用createEvent("MutationEvents") 创建一个包含
initMutationEvent() 方法的变动事件对象。这个方法接受的参数包括: type 、bubbles 、
cancelable、relatedNode、preValue、newValue、attrName 和attrChange。下面来看一个模
拟变动事件的例子。
var event = document.createEvent("MutationEvents");
event.initMutationEvent("DOMNodeInserted", true, false, someNode, "","","",0);
targ et.dispatchEvent(event);
以上代码模拟了DOMNodeInserted
- 自定义DOM 事件
创建新的自定义事件,可以调用createEvent("CustomEvent")。返回的对象有一个名为initCustomEvent()的方法
var div = document.getElementById("myDiv"),
event;
EventUtil.addHandler(div, "myevent", function(event) {
alert("DIV: " + event.detail);
});
EventUtil.addHandler(document, "myevent", function(event) {
alert("DOCUMENT: " + event.detail);
});
if (document.implementation.hasFeature("CustomEvents", "3.0")) {
event = document.createEvent("CustomEvent");
event.initCustomEvent("myevent", true, false, "Hello world!");
div.dispatchEvent(event);
}
创建了一个冒泡事件"myevent"。而event.detail 的值被设置成了一个简单的字符串,
然后在
元素和document 上侦听这个事件。因为initCustomEvent()方法已经指定这个事件应
该冒泡,所以浏览器会负责将事件向上冒泡到document。
支持自定义DOM事件的浏览器有IE9+和Firefox 6+。
13.6.2 IE中的事件模拟
IE8之前的版本
思路相似:先创建event 对象,然后为其指定相应的信息,然后再使用该对象来触发事件
调用document.createEventObject()方法可以在IE 中创建event 对象。但与DOM方式不同的是,这个方法不接受参数,结果会返回一个通用的event 对象
最后一步就是在目标上调用fireEvent()方法
fireEvent(事件处理程序的名称,event对象)
在调用fireEvent()方法时,会自动为event 对象添加srcElement 和type 属性
其他属性则都是必须通过手工添加的。换句话说,模拟任
何IE 支持的事件都采用相同的模式。例如,下面的代码模拟了在一个按钮上触发click 事件过程
var btn = document.getElementById("myBtn");
//创建事件对象
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);
//触发keypress事件
var textbox = document.getElementById("myTextbox");
//创建事件对象
var event = document.createEventObject();
//初始化事件对象
event.altKey = false;
event.ctrlKey = false;
event.shiftKey = false;
event.keyCode = 65;
//触发事件
textbox.fireEvent("onkeypress", event);
January 18, 2014
var supportsDOM2Core = document.implementation.hasFeature("Core", "2.0");
var supportsDOM3Core = document.implementation.hasFeature("Core", "3.0");
var supportsDOM2HTML = document.implementation.hasFeature("HTML", "2.0");
var supportsDOM2Views = document.implementation.hasFeature("Views", "2.0");
var supportsDOM2XML = document.implementation.hasFeature("XML", "2.0");
混合svg写法
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>Example XHTML page</title>
</head>
<body>
<svg xmlns="http://www.w3.org/2000/svg" version="1.1" viewBox="0 0 100 100" style="width:100%; height:100%">
<rect x="0" y="0" width="100" height="100" style="fill:red" />
</svg>
</body>
</html>
在DOM2 级中,Node 类型包含下列特定于命名空间的属性。
localName:不带命名空间前缀的节点名称。
namespaceURI:命名空间URI 或者(在未指定的情况下是)null。
prefix:命名空间前缀或者(在未指定的情况下是)null。
nodeName 等于prefix+":"+ localName
<html>元素來說
localName:html
tagName:html
namespaceURI:http://www.w3.org/1999/xhtml
prefix:null
<s:svg>元素
localName:svg
tagName:s:svg
namespaceURI:http://www.w3.org/2000/svg
prefix:s
DOM3 级在此基础上更进一步,又引入了下列与命名空间有关的方法。
isDefaultNamespace(namespaceURI):在指定的namespaceURI 是当前节点的默认命名空
间的情况下返回true。
lookupNamespaceURI(prefix):返回给定prefix 的命名空间。
lookupPrefix(namespaceURI):返回给定namespaceURI 的前缀。
Document变化
只有在文档中存在两个或多个命名空间时,这些与命名空间有关的方法才是必需的。
//创建一个新的SVG 元素
var svg = document.createElementNS("http://www.w3.org/2000/svg", "svg");
//创建一个属于某个命名空间的新特性
var att = document.createAttributeNS("http://www.somewhere.com", "random");
//取得所有XHTML 元素
var elems = document.getElementsByTagNameNS("http://www.w3.org/1999/xhtml", "*");
Element变化
getAttributeNS(namespaceURI,localName):取得属于命名空间namespaceURI 且名为
localName 的特性。
getAttributeNodeNS(namespaceURI,localName)
getElementsByTagNameNS(namespaceURI, tagName)
hasAttributeNS(namespaceURI,localName)
removeAttriubteNS(namespaceURI,localName)
setAttributeNS(namespaceURI,qualifiedName,value)
setAttributeNodeNS(attNode)
除了第一个参数之外,这些方法与DOM1 级中相关方法的作用相同;第一个参数始终都是一个命
名空间URI。
NamedNodeMap变化
getNamedItemNS(namespaceURI,localName)取得属于命名空间namespaceURI 且名为
localName 的项。
removeNamedItemNS(namespaceURI,localName)
其它变化:
- DocumentType 类型的变化 类型新增了3 个属性:publicId、systemId 和internalSubset。
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
"http://www.w3.org/TR/html4/strict.dtd">
中的:publicId == "-//W3C//DTD HTML 4.01//EN",
systemId =="http://www.w3.org/TR/html4/strict.dtd"
alert(document.doctype.publicId);
alert(document.doctype.systemId);
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"
[<!ELEMENT name (#PCDATA)>] >
document.doctype.internalSubset //"<!ELEMENT name (#PCDATA)>"
- Document 类型的变化
importNode() - Node 类型的变化
isSupported()
与DOM1级为document.implementation 引入的hasFeature()方法类似,isSupported()方法用于确定当前节点具有什么能力
if (document.body.isSupported("HTML", "2.0")){
//执行只有"DOM2 级HTML"才支持的操作
}
DOM3 额外引入数据:setUserData(要设置的键,实际的数据(可以是任何数据类型),处理函数)
var value = document.body.getUserData("name");
//创建div
var div = document.createElement("div");
//添加数据
div.setUserData("name", "Nicholas", function(operation, key, value, src, dest) {
if (operation == 1) {
dest.setUserData(key, value, function() {});
}
});
//使用cloneNode复制时,会调用处理函数,从而将数据自动复制到副本
var newDiv = div.cloneNode(true);
//调用getUserData()时,返回与原始结点相同的值
alert(newDiv.getUserData("name")); //"Nicholas"
- 框架的变化
var iframe = document.getElementById("myIframe");
var iframeDoc = iframe.contentDocument; //在IE8 以前的版本中无效
兼容
对象,可以使用下列代码。
var iframe = document.getElementById("myIframe");
var iframeDoc = iframe.contentDocument || iframe.contentWindow.document;
cssText
在写入模式下,赋给cssText 的值会重写整个style 特性的值;也就是
说,以前通过style 特性指定的样式信息都将丢失。例如,如果通过style 特性为元素设置了边框,
然后再以不包含边框的规则重写cssText,那么就会抹去元素上的边框。下面是使用cssText 属性的
var div = document.getElementsByTagName('div')[0]
div.style.cssText = 'width:25px;height:100px;background-color:red'
console.log(div.style.cssText) //width:25px;height:100px;background-color:red
for (var i = 0; i < div.style.length; i++) {
alert(div.style[i]) //width/height/backgorund-color
alert(div.style.item(i))
console.log(div.style.getPropertyValue(div.style[i])) //25px 100px red
}
getPropertyValue()方法取得的始终都是CSS 属性值的字符串表
getPropertyCSSValue()它返回一个包含两个属性的CSSValue 对象,这两个属性分,别是:cssText 和cssValueType。
div.style.removeProperty('width') //移除
getComputedStyle() 要取得樣式的元素與一個為元素字條串如:after,第二個參數可以為null;
無論樣式表還是行間樣式;計算後的值
var myDiv = document.getElementById("myDiv");
var computedStyle = document.defaultView.getComputedStyle(myDiv, null);
alert(computedStyle.backgroundColor); // "red"
alert(computedStyle.width); // "100px"
alert(computedStyle.height); // "200px"
alert(computedStyle.border); // 在某些浏览器中是"1px solid black"
IE下
var myDiv = document.getElementById("myDiv");
var computedStyle = myDiv.currentStyle;
alert(computedStyle.backgroundColor); //"red"
alert(computedStyle.width); //"100px"
alert(computedStyle.height); //"200px"
alert(computedStyle.border); //undefined
綜合
function getStyle(obj, attr) {
if (obj.currentStyle) {
return obj.currentStyle[attr]
} else {
return getComputedStyle(obj, false)[attr]
}
};
function getStyleSheet(element){
return element.sheet || element.styleSheet;
}
//取得第一个<link/>元素引入的样式表
var link = document.getElementsByTagName("link")[0];
var sheet = getStyleSheet(link);
var sheet = document.styleSheets[0];
var rules = sheet.cssRules || sheet.rules; //取得规则列表
var rule = rules[0]; //取得第一条规则
alert(rule.selectorText); //"div.box"
alert(rule.style.cssText); //完整的CSS 代码
alert(rule.style.backgroundColor); //"blue"
alert(rule.style.width); //"100px"
alert(rule.style.height); //"200px"
<style>.box{width:100px;}</style> ----sheet = document.styleSheets[0];
<link rel="stylesheet" href="style.css">----sheet = document.styleSheets[1];
<style>.box{height}</style> --sheet = document.styleSheets[2];
var rules = sheet.cssRules || sheet.rules; //取得规则列表
為每一個sheet裏的每一條;{}裏算一條
必须要注意的是,以这种方式修改规则会影响页面中适用于该规则的所有元素。换句话说,如果有两个带有box 类的
元素,那么这两个元素都会应用修改后的样式。
var sheet = document.styleSheets[0];
var rules = sheet.cssRules || sheet.rules; //取得规则列表
var rule = rules[0]; //取得第一条规则
rule.style.backgroundColor = "yellow"
function getTop(o) {
var oTop = o.offsetTop;
var current = o.offsetParent;
while (current !== null) {
oTop += current.offsetTop;
current = current.offsetParent;
}
return oTop;
}
alert(getTop(box))
所以视口
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
};
}
}
console.log(getViewport())

scrollHeight/scrollWidth/scrollLeft/scrollTop
有些元素(例如<html>元素),即使没有执行任何代码也能自动地添加滚动条;但另外一些元素,则需要通过CSS 的
overflow 属性进行设置才能滚动
scrollWidth 和scrollHeight 主要用于确定元素内容的实际大小
无滚动条时:scrollWidth = clientWidth
实际页面大小:document.documentElement.scrollHeight
视口大小:document.documentElement.clientHeight
无滚动条时:
IE7 chrome
document.documentElement.scrollHeight(页面占用元素大小) < document.documentElement.clientHeight(视口大小)
IE8 /IE9 /IE10 /IE11 firfox
document.documentElement.scrollHeight == document.documentElement.clientHeight
getBoundingClientRect()返回矩形,ie8(2.2),ie9(0,0)
,right 和left 的差值与offsetWidth 的值相等,而bottom 和top 的差值与offsetHeight
相等。而且,left 和top 属性大致等于使用本章前面定义的getElementLeft()和getElementTop()
函数取得的值
function getBoundingClientRect(element) {
var scrollTop = document.documentElement.scrollTop;
var scrollLeft = document.documentElement.scrollLeft;
if (element.getBoundingClientRect) {
if (typeof arguments.callee.offset != "number") {
var temp = document.createElement("div");
temp.style.cssText = "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 = element.getBoundingClientRect();
var offset = arguments.callee.offset;
return {
left: rect.left + offset,
right: rect.right + offset,
top: rect.top + offset,
bottom: rect.bottom + offset
};
} else {
var actualLeft = getElementLeft(element);
var actualTop = getElementTop(element);
return {
left: actualLeft - scrollLeft,
right: actualLeft + element.offsetWidth - scrollLeft,
top: actualTop - scrollTop,
bottom: actualTop + element.offsetHeight - scrollTop
}
}
}
alert(getBoundingClientRect(div).left)
alert(getBoundingClientRect(div).right)
alert(div.offsetWidth)
`
DOM2 级遍历和范围
检测是否有DOM2级能力(IE8返回false)
var supportsTraversals = document.implementation.hasFeature("Traversal", "2.0");
var supportsNodeIterator = (typeof document.createNodeIterator == "function");
var supportsTreeWalker = (typeof document.createTreeWalker == "function");
从document 开始依序向前,向下遍历,到开始根节点为止。NodeIterator
和TreeWalker 都以这种方式执行遍历。
createNodeIterator(root[起点],whatToShow[哪些节点数字代码],filter[NodeFilter对象,一个表示接受或拒绝的特定节点],entityReferenceExpansion[布尔值,表示是否扩展实体引用])
DOM2-----------------------------待放
January 17, 2014
DOM扩展
var div = document.querySelector('#div')
//返回NodeList實例
var div = document.querySelectorAll('.divClass')
console.log(div.item(0))
console.log(div[0])
console.log(div)
matchesSelector(CSS選擇符),如果匹配 true,否則 false
if (matchesSelector(div[0], '#div.divClass')) {
alert(true)
}
//兼容性
function matchesSelector(element, selector) {
if (element.matchesSelector) {
return element.matchesSelector(selector);
} else if (element.msMatchesSelector) {
return element.msMatchesSelector(selector);
} else if (element.mozMatchesSelector) {
return element.mozMatchesSelector(selector);
} else if (element.webkitMatchesSelector) {
return element.webkitMatchesSelector(selector);
} else {
throw new Error("Not supported.");
}
}
支持Element Traversal 规范的浏览器有IE 9+、Firefox 3.5+、Safari 4+、Chrome 和Opera 10+。
childElementCount:返回子元素(不包括文本节点和注释)的个数。
firstElementChild:指向第一个子元素;firstChild 的元素版。
lastElementChild:指向最后一个子元素;lastChild 的元素版。
previousElementSibling:指向前一个同辈元素;previousSibling 的元素版。
nextElementSibling:指向后一个同辈元素;nextSibling 的元素版。
二、困扰你我的NodeList与HTMLCollection
相同点:
1. 类数组。有length属性,可以用下标索引来访问其中的元素,但没有Array的slice等方法;
2. 只读。无法增删其中的元素;
3. 实时同步DOM树的变化。若DOM树有新元素加入,该类型的对象也会将新元素包含进来;
4. 可通过下标数字类型索引获取集合中指定位置的元素;
5. 可通过item({String | Number} 索引)方法获取集合中指定位置的元素,若通过索引找不到元素,则以第一个元素作为返回值。
不同点(主要表现在HTMLCollection比NodeList能力更强大):
1. HTMLCollection对象可通过namedItem({String} id或name)获取首个匹配的元素,若没有则返回null;
2. HTMLCollection对象可通过点方式获取第个id或name匹配的元素,若没有则返回undefined。
各浏览器选择器返回类型差别:
console.log(div instanceof NodeList) //true
//帶有.divClass.username的元素
var div = document.getElementsByClassName('divClass username')
console.log(div)
console.log(div instanceof HTMLCollection) //true;
傳統刪class
var classNames = div.className.split(/\s+/);
var pos = -1;
for(var i=0;i<classNames.length;i++){
if(classNames[i] == 'user'){
pos = i;
break;
}
}
classNames.splice(i,1);
div.className = classNames.join(' ');
classList,IE10+,chrome,firefox
div[0].classList.remove('username')
div[0].classList.add('current')
div[0].classList.toggle('divClass')
if(div[0].classList.contains('password') && div[0].classList.contains('disabled')){
alert(true)
}
焦点管理
var btn = document.getElementById('myButton')
btn.focus()
alert(document.activeElement == btn) //true
//文档加载完成时,document.activeElement保存的是document.body引用
//确定文档是否获得了焦点
alert(document.hasFocus()) //true
HTMLDocument的变化
1、readyState 两个值 loading:正在加载;complete:已经完成
if(document.readyState == 'complete'){
}
2、document.compatMode 的
值等于"CSS1Compat",而在混杂模式下,document.compatMode 的值等于"BackCompat"。
if (document.compatMode == "CSS1Compat") {
alert("Standards mode");
} else {
alert("Quirks mode");
}
3、head属性
Chrome 和Safari 5。
var head = document.head || document.getElementsByTagName("head")[0];
字符集属性
alert(document.charset); //"UTF-16"
document.charset = "UTF-8";
defaultCharset,表示根据默认浏览器及操作系统的设置,当前文档默认的字符集
应该是什么
if (document.charset != document.defaultCharset){
alert("Custom character set being used.");
}
自定义数据属性
data-,通过dataset访问 ,dataset是DOMStringMap的一个实例,每个data-name形式的属性都会有一个对应的属性,
比如,自定义属性是data-myname,
那映射中对应的属性就是myname)
<div id="myDiv" data-appId="12345" data-myname="Nicholas"></div>
var div = document.getElementById('myDiv')
//获取
var appId = div.dataset.appId;
var myName = div.dataset.myname;
//设置
div.dataset.appId = 123456
div.dataset.myname = 'elmok'
if(div.dataset.myname){
alert('hello ' + div.dataset.myname)
}
插入标记
innerHTML不同浏览器返回的值大小写可能不同
outerHTML返回包括外层
insertAdjacentHTML()两个参数
"beforebegin",在当前元素之前插入一个紧邻的同辈元素;
"afterbegin",在当前元素之下插入一个新的子元素或在第一个子元素之前再插入新的子元素;
"beforeend",在当前元素之下插入一个新的子元素或在最后一个子元素之后再插入新的子元素;
"afterend",在当前元素之后插入一个紧邻的同辈元素。
<div id="content"></div>
//作为前一个同辈元素插入
con.insertAdjacentHTML("beforebegin", "<p>beforebegin!</p>");
//作为第一个子元素插入
con.insertAdjacentHTML("afterbegin", "<p>afterbegin!</p>");
//作为最后一个子元素插入
con.insertAdjacentHTML("beforeend", "<p>beforeend!</p>");
//作为后一个同辈元素插入
con.insertAdjacentHTML("afterend", "<p>afterend!</p>");
之后
<p>beforebegin!</p>
<div id="content">
<p>afterbegin!</p>
<p>beforeend!</p>
</div>
<p>afterend!</p>
在使用innerHTML、
outerHTML 属性和insertAdjacentHTML()方法时,最好先手工删除要被替换的元素的所有事件处理
程序和JavaScript 对象属性
for (var i=0, len=values.length; i < len; i++){
ul.innerHTML += "<li>" + values[i] + "</li>"; //要避免这种频繁操作!!
}
//正确做法
var itemsHtml = "";
...
scrollIntoView(),滚动标准作法
如果给这个方法传入true 作为参数,或者不传入任何参数,那么窗口滚动之后会让调用元素的顶部与视口顶部尽可能平齐;
如果传入false 作为参数,调用元素会尽可能全部
出现在视口中,(可能的话,调用元素的底部会与视口顶部平齐。)不过顶部不一定平齐
只有调用才会出现在视口中,类似于a标签本页定位的效果
var btn = document.getElementById('btn')
var div = document.getElementById('content')
btn.onclick = function(){
div.scrollIntoView(true)
}
IE “文档模式”(document mode) 文档模式决定了你可以使用哪个级别的 CSS
要强制浏览器以某种模式渲染页面,可以使用 HTTP头部信息 X-UA-Compatible,或通过等价的 <meta>标签来设置:
//<meta http-equiv="X-UA-Compatible" content="IE=IEVersion">
<meta http-equiv="X-UA-Compatible" content="IE=EmulateIE7">
var mode = document.documentMode;
alert(mode) // 11/10/9/8/7/5....
children属性
。IE8及更早版本的 children 属性中也会包含注释节点,但 IE9之后的版本则 只返回元素节点
contains()方法.
经常需要知道某个节点是不是另一个节点的后代
alert(document.documentElement.contains(document.body)); //true
- innerText 属性
outerText 属性 //包括父级也替换
滚动
scrollIntoView()
scrollIntoViewIfNeeded(alignCenter):只在当前元素在视口中不可见的情况下,才滚
动浏览器窗口或容器元素,最终让它可见。如果当前元素在视口中可见,这个方法什么也不做。
如果将可选的alignCenter 参数设置为true,则表示尽量将元素显示在视口中部(垂直方向)。
Safari 和Chrome 实现了这个方法。
scrollByLines(lineCount):将元素的内容滚动指定的行高,lineCount 值可以是正值,
也可以是负值。Safari 和Chrome 实现了这个方法。
scrollByPages(pageCount):将元素的内容滚动指定的页面高度,具体高度由元素的高度决
定。Safari 和Chrome 实现了这个方法。
希望大家要注意的是,scrollIntoView()和scrollIntoViewIfNeeded()的作用对象是元素的
容器,而scrollByLines()和scrollByPages()影响的则是元素自身。下面还是来看几个示例吧。
//将页面主体滚动5 行
document.body.scrollByLines(5);
//在当前元素不可见的时候,让它进入浏览器的视口
document.images[0].scrollIntoViewIfNeeded();
//将页面主体往回滚动1 页
document.body.scrollByPages(-1);
由于scrollIntoView()是唯一一个所有浏览器都支持的方法,因此还是这个方法最常用。
January 15, 2014
Node.nodeType == 1 元素节点
Node.nodeType == 2 属性节点
Node.nodeType == 3 文本节点
<head>
<meta charset="UTF-8">
<title></title>
</head>

var h = document.getElementsByTagName('head')[0]
// h.nodeType == 1 && console.log('this is an elem')
h.nodeType == 1 && console.log(h.nodeName) //HEAD
//每个节点都有一个childNodes 属性,其中保存着一个NodeList 对象。即类数组对象
console.log(h.childNodes[0])
console.log(h.childNodes[1])
console.log(h.childNodes[2])
console.log(h.childNodes[3])
console.log(h.childNodes[4])
console.log(h.parentNode) //5
console.log(h.childNodes.length)
把NodeTypelist转为数组
function convertToArray(nodes) {
var array = null;
try {
array = Array.prototype.slice.call(nodes, 0); //针对非IE 浏览器
} catch (ex) {
array = new Array();
for (var i = 0, len = nodes.length; i < len; i++) {
array.push(nodes[i]);
}
}
return array;
}
每个Node都有一个parentNode属性,该属性指向文档树中的父节点;
nodeName //HEAD
parentNode //Html文档结构
childNodes //Nodelists节点集合
previousSibling //前一个
nextSibling //后一个
如果没有子节点,那么firstChild 和lastChild 的值均为null
hasChildNodes(),这个方法在节点包含一或多个子节点的情况下返回true;应该说,这是比查询childNodes
列表的length 属性更简单的方法。
h.hasChildNodes()
ownerDocument,所有节点的共同属性,指向整个文档节点
console.log(h.ownerDocument)
操作节点
末尾:
appendChild()相当于向childNodes列表尾部添加一个节点,,如果是已有节点,则相当于剪切;
中间:
insertBefore(),向childNodes列表放在特定的位置上
insertBefore(要插入的节点,作为参照的节点) 【插入之后按顺序前后排:要插入的节点,作为参照的节点】
插入节点后,被插
入的节点会变成参照节点的前一个同胞节点(previousSibling),
returnedNode = someNode.insertBefore(newNode, null);
alert(newNode == someNode.lastChild); //true
//插入后成为第一个子节点
var returnedNode = someNode.insertBefore(newNode, someNode.firstChild);
alert(returnedNode == newNode); //true
alert(newNode == someNode.firstChild); //true
//插入到最后一个子节点前面
returnedNode = someNode.insertBefore(newNode, someNode.lastChild);
alert(newNode == someNode.childNodes[someNode.childNodes.length-2]); //true
替换:
replaceChild(要插入的节点,要替换的节点)
//替换第一个子节点
var returnedNode = someNode.replaceChild(newNode, someNode.firstChild);
//替换最后一个子节点
returnedNode = someNode.replaceChild(newNode, someNode.lastChild);
移除:
removeChild(要移除的节点)
前面介绍的四个方法操作的都是某个节点的子节点,也就是说,要使用这几个方法必须先取得父节
点(使用parentNode 属性)。另外,并不是所有类型的节点都有子节点,如果在不支持子节点的节点
上调用了这些方法,将会导致错误发生。
共有的节点方法:
cloneNode(true/false),需要再使用 appendChild()/insertBefore()/replaceChild()
normalize() /这个方法唯一的作用就是处理文档树中的文本节点
Document类型
nodeType 的值为9;
nodeName 的值为"#document";
nodeValue 的值为null;
parentNode 的值为null;
ownerDocument 的值为 null;
Document 节点的子节点可以是DocumentType、Element、ProcessingInstruction
或Comment,
内置访问子节点的快捷方式:
document.documentElement属性
document.documentElement ==
document.childNodes[0] ==
document.firstChild ==
document.body 属性,直接指向<body>元素;
另一个子节点可能是:(浏览器支持有限)
var doctype = document.doctype; //取得对<!DOCTYPE>的引用
文档信息
document对象属性:
//取得文档标题
var originalTitle = document.title;
//设置文档标题
document.title = "New page title";
//取得完整的URL
var url = document.URL;
//取得域名
var domain = document.domain;
//取得来源页面的URL
var referrer = document.referrer;
IE7下,name與ID相同的不同元素使用doc..ById會返回name的元素
alert(document.getElementById('myelem').nodeName)
不要讓表單字段的name與其他ID相同
var imgs = document.getElementsByTagName('img')
var imgsname = imgs.namedItem('myimgName')
取得單選按鈕【常用】 getElementByName('color');
特殊集合
document.anchors:包括name屬性的a元素
document.links:包含所有帶href特性的a元素
document.images:包含所img元素
document.forms:包含所form元素
一個element類型:
console.log(box.nodeType) //1
console.log(box.nodeName) //DIV
console.log(box.nodeValue) //null
console.log(box.parentNode) //<body......body>
console.log(box.childNodes) //[elem..text..com...]
console.log(box.tagName) //DIV tagName == nodeName
HTML元素,可读可写
alert(div.id); //"myDiv""
alert(div.className); //"bd"
alert(div.title); //"Body text"
alert(div.lang); //"en"
alert(div.dir); //"ltr"
取得特性
alert(div.getAttribute("id")); //"myDiv"
alert(div.getAttribute("class")); //"bd"
alert(div.getAttribute("title")); //"Body text"
alert(div.getAttribute("lang")); //"en"
alert(div.getAttribute("dir")); //"ltr"
不存在返回null;
自定义属性应该加上data-前缀以便验证
var div = document.getElementById('myDiv')
alert(div.my_special_attribute); //undefined(IE<8 弹 hello ,其它弹undefined)
设置属性:
box.setAttribute('style') //如果不写出错 box.setAttribute('style','')//正确
自定义属性不能简单地使用.来设置
box.mycolor = 'red'; //使用.设置
alert(box.getAttribute('mycolor')) //null;(IE9<可弹出)
//setAttributte配套使用;
box.setAttribute('myspace','300px')
alert(box.getAttribute('myspace'))
div.removeAttribute("class");完全清除,彻底删除元素特性;
- attributes 属性
Element 类型是使用attributes 属性的唯一一个DOM 节点类型。attributes 属性中包含一个
NamedNodeMap,与NodeList 类似,也是一个“动态”的集合。元素的每一个特性都由一个Attr 节
点表示,每个节点都保存在NamedNodeMap 对象中。NamedNodeMap 对象拥有下列方法

遍历元素特性序列化
function outputAttributes(element) {
var pairs = new Array(),
attrName,
attrValue,
i,
len;
for (i = 0, len = element.attributes.length; i < len; i++) {
attrName = element.attributes[i].nodeName;
attrValue = element.attributes[i].nodeValue;
if (element.attributes[i].specified) {
pairs.push(attrName + "=\"" + attrValue + "\"");
}
}
return pairs.join(" ");
}
console.log(outputAttributes(box)) // id="box" style="font-size:14px;color:#000" class="boxclass"
创建元素
``javascript
var div = document.body.appendChild('div')
div.id = mydiv
document.body.appendChild(div)
创建文本
var box = document.getElementById('box')
if(box.childNodes[0].nodeType == 3 ){
alert(123)
}
alert(box.childNodes[0].nodeValue)
alert(box.childNodes[0].data)
Text类型
var e = document.createElement('div')
e.className = 'message'
var atnode = document.createTextNode('fuck ')
e.appendChild(atnode)
var atnode2 = document.createTextNode('world')
e.appendChild(atnode2)
alert(e.childNodes.length) //2 个节点
e.normalize() //规范化成1个(合并)
alert(e.childNodes.length) //1
alert(e.firstChild.nodeValue) //fuck world
分割 splitText()
var e = document.createElement('div')
e.className = 'message'
var Tnode = document.createTextNode('hello world')
e.appendChild(Tnode)
document.body.appendChild(e);
var newNode = e.firstChild.splitText(2)
alert(e.firstChild.nodeValue) //he 从2的位置开始分割
comment类型 注释类型 nodeType == 8
CDATASection类型 XML 文档,表示CDATA区域 nodeType == 4
DocumentType类型 nodeType == 10
DocumentFragment类型 nodeType == 11;
Attr类型 存在于元素的attributes属性中的节点,nodeType == 11; ??
创建动态脚本:
function loadScript(url) {
var script = document.createElement('script')
script.type = 'text/javascript'
script.src = url
document.body.appendChild(script)
}
loadScript('main.js')
代码执行
function loadScriptString(code) {
var script = document.createElement('script')
script.type = 'text/javascript'
try {
script.appendChild(document.createTextNode(code))
} catch (ex) {
script.text = code;
}
document.body.appendChild(script)
}
loadScriptString("function sayHi(){alert('hi')}")`
其实效果跟 eval("function sayName(){alert('name')}") 一样;
动态样式
function loadStyles(url) {
var link = document.createElement('link')
link.rel = 'stylesheet'
link.type = 'text/css'
link.href = url
var head = document.getElementsByTagName('head')[0]
head.appendChild(link)
}
loadStyles('style.css')
function loadStyleString(css) {
var style = document.createElement('style')
style.type = 'text/css'
try {
style.appendChild(document.createTextNode(css))
} catch (ex) {
style.style.cssText = css;
}
document.getElementsByTagName('head')[0].appendChild(style);
}
loadStyleString('body{background:#1F78BF}')
操作表格
cell 11 |
cell 22 |
cell 33 |
cell 44 |
var table = document.createElement('table')
table.border = 1;
table.width = '100%'
//tbody
var tbody = document.createElement('tbody')
table.appendChild(tbody)
//第一行
tbody.insertRow(0)
tbody.rows[0].insertCell(0);
tbody.rows[0].cells[0].appendChild(document.createTextNode('cell 11'))
tbody.rows[0].insertCell(1);
tbody.rows[0].cells[1].appendChild(document.createTextNode('cell 22'))
//第二行
tbody.insertRow(1)
tbody.rows[1].insertCell(0);
tbody.rows[1].cells[0].appendChild(document.createTextNode('cell 33'))
tbody.rows[1].insertCell(1);
tbody.rows[1].cells[1].appendChild(document.createTextNode('cell 44'))
document.body.appendChild(table)
**HTMLCollection、NodeList以及NamedNodeMap这三个集合都是“动态的”,每当文档发生变化时,他们都会更新。他们将始终保持这最新、最准确的消息。且看以下程序:**
var divs = document.getElementsByTagName('div'),
i, div;
for (i = 0; i < divs.length; i++) {
div = document.createElement('div')
document.body.appendChild(div)
}
//以上代码,第一次取得所有div 元素的HTMLCollection,下次取得会更新,造成死循环
//正确使用
var divs = document.getElementsByTagName('div'),
i, len, div;
for (i = 0, len = divs.length; i < len; i++) {
div = document.createElement('div')
document.body.appendChild(div)
}
<hr />
DOM元素的特性(Attribute) 和 属性(Property)
Attribute特性: dom节点自带的属性,例如html中常用的id、class、title、align等:
//赋值:之后立即体现到DOM ,如果是标准特性,也会关联到相对应的属性值 ;
div1.setAttribute('class', 'a');
div1.setAttribute('title1', 'c');
Property属性: 而Property是这个DOM元素作为对象,其附加的内容,例如childNodes、firstChild等:
//取值,用.
var id = div1.id;
var attrs = div1.attributes;
//上面代码中的div1.attributes是取的attributes这一属性,取出来保存到attrs变量中,attrs就成了一个NamedNodeList类型的对象,里面存储了若干个Attr类型。
//赋值 :对属性Property可以赋任何类型的值,而对特性Attribute只能赋值字符串!
div1.className = 'a';
<hr >
NodeList v.s. HTMLCollection
Node及对应集合NodeList
Element(继承Node)及对应集合HTMLCollection
Document(继承Node)
- 1
- 2
- 3
- 4
- ...
- 7
- 后一页 »