响应用户操作和事件
事件就是操作检测与脚本执行的组合,或者基于检测到的操作类型在某个对象上调用事件侦听器(事件处理程序)。
事件的类型
事件可以分为几种类型:对象事件,鼠标事件,键盘事件(只适用于document对象),表单事件,自定义事件。
控制事件流和注册事件侦听器
事件流描述的是从页面中接收事件的顺序;事件侦听器,就是一个常规的JavaScript函数。
三个阶段和三个模型
事件冒泡:指的是目标元素的事件方法优先并且会被首先执行,然后,事件会向外传播到每个祖先元素,直至document对象。由Microsoft IE提出的冒泡型事件流;
事件捕获:把优先权赋予最外层的祖先元素,事件相应地被由外向内传播,直至抵达目标元素。由Netscape提出的捕获型事件流;
在W3C DOM2 事件模型中,当目标元素被单击时,首先是经过事件捕获阶段,接着是处于目标阶段,最后是事件冒泡阶段;
阻止冒泡
可以在事件对象上调用stopPropagation()方法,对于IE, 需要将事件的cancelBubble属性设置为true。
取消默认动作
与事件流有关的最后一个问题就是默认动作。DOM2 事件规范中提供了使用事件的preventDefault()方法取消默认动作的方式。
注册事件的四种事件模型
1. 嵌入式注册模型
例如:
<a href="http://www.google.com" onclick = "alert('11'); return false;">ie</a>
缺点:使标记混乱不堪
2. 传统的事件模型
例如:
window.onload = function(){}
传统的方法从属于浏览器默认的事件流,没有办法指定是在捕获阶段还是在冒泡阶段调用事件。
3. IE事件模型
例如:
window.attachEvent('onload', function(){});
缺点:只对IE有效,对其他浏览器毫无用处;其次,this 引用的是原始JavaScript函数,而不是附加事件侦听器的那个对象。
4. W3C DOM2 事件模型
DOM2事件规范中包含addEventListener()和removeEventListener()方法,这两个方法接受3个参数(事件,事件侦听器,事件阶段),第三个参数是true表示事件侦听器在捕获阶段内执行,否则,如果为false,则会在冒泡阶段发生(默认是false)。此外,W3C 采取了去掉on前缀的方案,因此所有事件都必须使用事件名称而非传统的方法名称来标识。例如:
window.addEventListener('load', function(e){}, false);
//在W3C的模型中,事件侦听器会取得一个表示事件自身的参数。但在IE中,事件对象被保存在window.event中。
DOM2 事件规范中的Event对象属性和方法
- type: 是一个包含事件名称的字符串值;
- target: 是DOM文档中最早调用事件序列的目标对象,IE浏览器提供的是srcElement属性;
- currentTarget: 是当前正在处理的事件侦听器所在的事件流中的DOM元素;
- preventDefault(): 取消对象的默认动作,比如:浏览器重定向到一个锚元素的href属性的动作;
- stopPropagation(): 用于停止事件流的进一步执行,包括捕获阶段,目标对象和冒泡阶段;
DOM2 事件规范中的MouseEvent对象属性
处理鼠标相对于文档原点的位置的兼容性处理:
function getPointerPositionInDocument(event) {
let e = event || window.event;
let x = e.pageX || (e.clientX +
document.documentElement.scrollLeft || document.body.scrollLeft);
let y = e.pageY || (e.clientY +
document.documentElement.scrollTop || document.body.scrollTop);
return { 'x': x, 'y': y };
}
处理文档/页面水平/垂直方向滚动的像素值:
/*pageXOffset, pageYOffset 属性是 scrollX, scrollY 属性的别名。window.pageXOffset == window.scrollX; // 总是 true
为了跨浏览器兼容性,请使用 window.pageXOffset 代替 window.scrollX。另外,旧版本的 IE(<9)两个属性都不支持,必须通过其他的非标准属性来解决此问题。
完整的兼容性代码如下:
*/
var supportPageOffset = window.pageXOffset !== undefined;
var isCSS1Compat = ((document.compatMode || "") === "CSS1Compat");
var x = supportPageOffset ? window.pageXOffset : isCSS1Compat ? document.documentElement.scrollLeft : document.body.scrollLeft;
var y = supportPageOffset ? window.pageYOffset : isCSS1Compat ? document.documentElement.scrollTop : document.body.scrollTop;
//代码来自MDN:https://developer.mozilla.org/zh-CN/docs/Web/API/Window/scrollY
动态修改样式和层叠样式表
CSSStyleDeclaration对象
这个对象用于表示一个元素的style属性。
- cssText: 包含以字符串形式表示的全部规则;
- parentRule: 将引用CSSStyleRule对象;
- getPropertyValue(propertyName): 返回一个字符串形式的CSS样式属性值;
- removeProperty(propertyName): 从声明中移除特定的属性;
- setProperty(propertyName, value, priority): 用于设置特定CSS属性的值;
将样式置于DOM脚本之外
1. style 属性
当在小范围内修改表现时,你可能会经常使用 HTMLElement 元素的 style 属性来修改其表现。但修改style属性存在如下两个主要问题:
- 使用 style 属性将设计样式嵌入到行为层的DOM脚本中,并不比在语义标记中使用 style 属性更好。
- 通过 style 属性只能访问到在元素的style属性中以嵌入方式声明的CSS属性。换句话说,通过style属性无法访问由多重样式层叠表而来或者从父元素继承的任何css属性。
2. setProperty(propertyName, value, priority)
除了可以使用style属性直接设置css属性(例如:element.style.color = 'red';
)外,DOM2样式规范为CSSStyleDeclaration对象定义了相应的方法,比如setProperty()就使用固有的带连字符的CSS属性名称和值:例如:element.style.setProperty('background-color', 'red');
。但非标准的浏览器(例如IE)不支持这种方法。
3. 基于className切换样式
使用方法:element.className = 'newClassName';
,此方法的优点是在所有浏览器中都有效。
访问计算样式
DOM2 样式规范在document.defaultView中包含了一个名叫getComputedStyle()的方法,恰好是为这个目的而设计的。该方法返回一个只读的CSSStyleDeclaration对象,其中包含特定元素的所有计算样式,而不仅仅是以嵌入方式定义的样式。