* DOM *
---------------------------------------------------------------------------
1. 遍历DOM
1) 要注意处理空格(空格类文本占用一个节点)
2) DOM家谱中的定位指针:
firstChild <--> parentNode
lastChild <--> parentNode
nextSibling <--> previousSibling
3) 节点类型:
--> 元素 nodeType = 1
--> 文本 nodeType = 3
--> 文档 nodeType = 9 在HTML文档内,即<html>元素
4) 标准DOM方法
document.getElementById('id');
document.getElementsByTagName('tagName');
2. 等待HTML DOM的加载
1) 浏览器渲染和操作的大致顺序:
A. HTML解析完毕
B. 外部脚本和样式表加载完毕
C. 脚本在文档内解析并执行
D. HTML DOM完全构造起来
E. 图片和外部内容加载
F. 网页完成加载
2) 等待加载策略
A. 等待整个页面的加载
利用window对象的load事件绑定一个函数
缺点: 慢! 若页面包含大量图片、视频等,需等待很长时间才能执行javascript
B. 等待大部分DOM的加载
在页面最后元素之前嵌入脚本(通常认为是不合理的,不推荐使用)
C. 判断DOM何时加载完毕
检查HTML DOM是否可用的要点:
(1) document
(2) document.getElementsByTagName 和 document.getElementById
(3) document.body 额外补充(理论上使用前一个检查足够判断)
实现:
function domReady(fn){ if(domReady.done) return fn(); if(domReady.timer){ domReady.ready.push(fn); }else{ domReady.ready = [fn]; domReady.timer = setInterval(isDOMReady, 13); } } function isDOMReady(){ if(domReady.done) return false; if(document && document.getElementsByTagName && document.getElementById && document.body){ clearInterval(domReady.timer); domReady.timer = null; for(var i=0,len=domReady.ready.length; i<len; ++i) domReady.ready[i](); domReady.ready = null; domReady.done = true; } }
3. 在HTML文档中查找元素
1) 通过类值查找元素
2) 使用css选择器查找元素
3) XPath
4. 获取元素的内容
1) 获取元素内文本
A. 所有非Mozilla的浏览器中都有一个 innerText 属性可获取文本
B. 元素并非直接包含文本,而是包含在一个子文本节点中
2) 获取元素内HTML
A. 所有现代浏览器都实现的属性: innerHTML
B. 依赖于浏览器的实现,实现的潜在问题:
--> 基于Mozilla的浏览器不会返回<style>元素
--> IE返回的元素字符都是大写
--> 只能在HTML DOM文档中使用,在XML DOM文档中返回null
5. 操作元素特性
1) 获取和设置特性的值
A. 兼容XML DOM的方法: getAttribute('name'); setAttribute('value', 'zhangsan');
B. HTML DOM文档的额外方式: var name = elem.name; elem.value = zhangsan;
C. 特殊情况:
--> getAttribute/setAttribute对class属性不一定通用(如IE会返回null)
--> 简单的写法应该形如: elem.className 而非 elem.class(class是js的关键字)
--> label标签的for属性也是如此: elem.htmlFor
--> 一些css属性: elem.style.cssFloat, elem.style.cssText
--> 处理方式: name = {'for': 'htmlFor', 'class': 'className'}[name] || name
6. 修改DOM
1) 创建
document.createElement 创建新元素,它不会马上插入到DOM中
document.createTextNode 创建文本节点
2) 插入
parentNode.insertBefore(nodeToInsert, beforeNode);
不指定beforeNode时在最后插入,类似:
parentNode.appendChild(nodeToInser);
3) 注入
利用innerHTML属性. 缺陷:
--> 对于XML DOM不通用
--> innerHTML完全删除了元素内容的任何节点,没法像DOM方法一样追加或插入
4) 删除
parentNode.removeChild(nodeToRemove);
* 事件 *
---------------------------------------------------------------------------
1. 事件简介
1) 异步事件与线程
JavaScript事件模型: 不使用任何线程,完全是异步的
--> JavaScript目前不存在线程,最接近线程的是使用setTimeout()回调函数
也就是说,js代码的执行,是阻塞的
--> 异步回调: 当一个DOM元素触发某个特定事件时,通过一个回调函数来处理它
2) 事件阶段
--> 捕获: 事件会以 document => <body> => .... 的顺序捕获
--> 冒泡: 事件处理函数反向冒泡执行
2. 常见事件特征
1) 事件对象
--> IE的实现与W3C规范有差别: 它使用独立的全局事件对象window.event
--> 其他浏览器使用独立的包含事件对象的参数传递
document.getElementById('id').onclick = function(e){
e = e || window.event;
//......
};
2) this关键字
--> 只有部分浏览器和部分方法能正常运行并将this等同于当前元素
--> 使用this关键字处理事件相关代码相当便利
3) 取消事件冒泡
--> 标准浏览器: e.stopPropagation();
--> IE浏览器: window.event.cancelBubble = true;
4) 重载浏览器的默认行为
--> 浏览器的默认行为在捕获阶段、冒泡阶段都会发生
--> 阻止事件冒泡或者完全没有绑定事件并不会影响默认行为的执行
--> 阻止默认行为的途径:
A. 标准浏览器: e.preventDefault();
B. IE浏览器: window.event.returnValue = false;
--> 防止默认行为是由浏览器决定的,未必总生效(尤其是在文本域中防止敲击和<iframe>内的行为)
3. 绑定事件监听函数
1) 传统绑定
目前为止,绑定事件处理函数最简单且兼容性最好的方式
document.body.onkeypress = function(){...};
window.onload = function(){...};
--> 优点: A. 简单,稳定,兼容;
B. 处理事件时,this关键字引用的是当前元素
--> 缺点: A. 只会在事件冒泡中运行;
B. 只能绑定一个事件处理函数;
C. 事件对象参数仅对非IE浏览器有效
2) W3C方式
使用: elem.addEventListener(事件名称, 处理事件的函数, 启用/禁用事件捕获的标示);
document.getElementById('id').addEventListener('mouseover', function(e){
this.style.border = '1px solid red';
}, false);
--> 优点: A. 同时支持捕获和冒泡阶段(true捕获,false冒泡);
B. this关键字引用当前元素;
C. 可以获取事件对象参数;
D. 同一元素绑定多个事件时不会覆盖
--> 缺点: IE不支持
3) IE方式
使用: elem.attachEvent(事件名称, 处理事件的函数);
--> 优点: 同一元素绑定多个事件时不会覆盖
--> 缺点: A. 仅支持事件冒泡阶段;
B. this关键字指向window对象而非当前元素;
C. 事件对象仅存在于window.event参数中;
D. 事件必须以ontype的形式命名,如onclick;
E. 仅IE可用,其他标准浏览器不支持
4) 通用方法
function addEvent(element, type, handler){
if(!handler.$$guid)
handler.$$guid = addEvent.guid++;
if(!element.events)
element.events = {};
var handlers = element.events[type];
if(!handlers){
handlers = element.events[type] = {};
if(element['on'+type]){
handlers[0] = element['on'+type];
}
}
handlers[handler.$$guid] = handler;
element['on'+type] = handleEvent;
}
addEvent.guid = 1;
function removeEvent(element, type, handler){
if(element.events && element.events[type]){
delete element.events[type][handler.$$guid];
}
}
function handleEvent(event){
var returnValue = true;
event = event || fixEvent(window.event);
var handlers = this.events[event.type];
for(var i in handlers){
this.$$handleEvent = handlers[i];
if(this.$$handleEvent(event)===false){
returnValue = false;
}
}
return returnValue;
}
function fixEvent(event){
event.preventDefault = fixEvent.preventDefault;
event.stopPropagation = fixEvent.stopPropagation;
return event;
}
fixEvent.preventDefault = function(){
this.returnValue = false;
};
fixEvent.stopPropagation = function(){
this.cancelBubble = true;
};
4. 事件类型
1) 鼠标事件
2) 键盘事件
3) UI事件