一、事件
1、事件绑定:
1. elem.onxxx = function(){},this指向elem,只能绑定一个处理函数,基本等同于写在HTML行间(句柄写法)
2. elem.addEventListener('事件类型',处理函数,false),this指向elem,可绑定多个处理函数
3. elem.attachEvent('on'+事件类型, 处理函数),this指向window。(解决方案:外部单独写处理函数,里面的函数体调用真正的处理函数,call的方式),可绑定多个处理函数,而且同一个函数绑定多次可以多次执行。
经典鄙视题:给li列表循环绑定click事件,输出他们的索引。
var oLi = document.getElementsByTagName('li');
for(var i = 0; i < oLi.length; i++){
(function(j){
oLi[i].onclick = function(){
console.log(j);
}
}(i))
}
2、解除事件:
1. elem.onxxx = null/false,给赋一个空值就完事儿
2. elem.removeEventListener('事件类型',同一个函数引用,false),绑定匿名函数,无法解除
3. elem.detachEvent('on'+事件类型, 同一个函数引用)
封装绑定事件函数,兼容所有浏览器
function addEvent(elem, type, handle){
if(elem.addEventListener){
elem.addEventListener(type, handle, false);
}else if(elem.attachEvent){
elem.attachEvent('on' + type, function(){
handle.call(elem);//解决this指向的问题
})
}else{
elem['on' + type] = handle;
}
}
二、事件处理模型:冒泡、捕获(触发顺序为:首先捕获,然后源元素事件执行,最后冒泡!!)
1、冒泡:(focus, blur, change, submit, reset, select等事件不冒泡)
根据结构上(非视觉)嵌套关系:son -> father -> grandfather -> ... 一直往上冒泡
2、捕获:(IE没有。。)
和冒泡相反,自父元素捕获至事件源元素,第三个参数填true
(另一种只有IE能用的捕获:div.setCapture()会把页面上的事件都获取到div身上,div.releaseCapture()释放)
3、取消冒泡:
W3C:e.stopPropagation(处理函数上传一个参数e,系统会返回一个事件对象,上面包含这个方法)
IE&chrome:e.cancelBubble = true
4、阻止默认事件:(表单提交页面刷新,a标签跳转,右键菜单等)
return false,只对句柄方式绑定的事件(elem.onxxx = function(){})有效
e.preventDefault(),(a链接的href里面写javascript:void(false)也可以取消a链接默认事件)
e.returnValue = false,兼容IE
5、事件对象:e || window.event
6、事件源对象:event.target || event.srcElement
7、事件委托:根据冒泡,直接都交给上层处理
练习:实现一个拖拽函数
function drag(elem){
var elem = document.querySelector(elem);
var disX,
disY;
elem.addEventListener('mousedown',function(e){
var event = e || window.event;
disX = e.clientX - elem.offsetLeft;
disY = e.clientY - elem.offsetTop;
document.addEventListener('mousemove',handle, false)
elem.addEventListener('mouseup', function(){
document.removeEventListener('mousemove',handle, false)
}, false)
}, false)
function handle(e){
var event = e || window.event;
elem.style.left = e.clientX - disX + 'px';
elem.style.top = e.clientY - disY + 'px';
}
}
三、事件类型
1、鼠标类事件:
1. 需知click只监听左键;up、down区分鼠标左右键;
2. 事件对象上有button属性,0、1、2分别代表左、中、右;
3. 在移动端移动端down、up、click等失效。用touchstart、touchmove、touchend代替
2、键盘类事件:
1. down、press(会连续触发,比如游戏的前进后退键。down监测所有按键,press监测字符类按键返回ASCII码)、up
2. String.fromCharCode(unicode码) ,返回字符
3、文本操作事件:
1. input:文本但凡变化就触发
2. change:聚焦和失焦两个状态是否有改变
3. focus:聚焦
4. blur:失焦
完善一个input框
<input type="text" name="username" style="color: #999" value="请输入用户名" onfocus="if(this.value=='请输入用户名'){this.value='';this.style.color='#424242'}" onblur="if(this.value==''){this.value='请输入用户名';this.style.color='#999'}">
4、窗体类事件:
1. window.scroll(ie6没有fixed定位,用position:absolute模拟,top = 原top+滚动条的位置)
2. load(xxx.onload,慢!!!renderTree构建完毕,所有资源加载完成,onload才会执行)
四、关于异步加载:(js会阻塞文档,加载工具方法的js没必要阻塞文档)
1. domTree,构建时深度优先,domTree构建完成代表所有dom节点解析完毕
2. cssTree,构建时深度优先
3. domTree + cssTree = renderTree(渲染引擎开始绘制页面)
一些操作会引起reflow重排,比如dom节点的删除、添加、宽高,位置变化、offsetWidth、offsetLeft
还有一些操作会引起repaint重绘,危害略小于重排
1、异步加载的几种方法:
1. defer:只有IE能用,<script type="text/javascript" src="" defer="defer"></script>等到dom文档解析完才会被执行
2. async:<script type="text/javascript" src="" async="async"></script>加载完就执行,只能加载外部脚本
3. 按需加载
2、js加载时间线(非常重要)
创建document对象,开始解析web页面。document.readyState = 'loading'
遇到link外部css,异步加载
遇到script外部js,未设置异步的,阻塞文档
遇到script外部js,设置异步的,异步加载(禁止使用document.write,他能把之前的文档流清空)
遇到img,正常解析dom,异步加载src
文档解析完成(domTree完成),document.readyState = 'interactive'
文档解析完成,设置defer的脚本执行
文档解析完成,document对象触发DOMContentLoaded(只能用addEventListener绑定,jq的$(document).ready就是这个时候),浏览器转为事件驱动
整个页面加载完毕,document.readState="complete",即window.onload
以上内容属二哥原创,整理自 "渡一教育Javascript课程" ,一个值得推荐的"渡一教育"。