事件基础和事件委托
事件委托
事件的兼容性问题:
1、事件对象本身的获得方式不同,IE是用全局的window.event,chrome是浏览器自动会给把事件对象传给事件触发的方法,作为此方法的第一个参数。
1.1、chrome也是支持window.event的
2、事件传播和阻止事件传播的方式:ie是e.cancelBubble=true;标准浏览器是用的e.stopPropagation()
3、取消事件默认行为:IE是e.returnValue=false;标准浏览器用的是e.preventDefault();
4、触发事件的事件源不一样:IE是e.srcElement,标准浏览器是e.target
5、IE不支持e.pageX、e.pageY
6、最大的兼容性问题在于对DOM2级事件的支持上
什么DOM2级事件:就是在DOM的第二个版本中,实现的事件绑定方式
DOM0 (本身没有DOM0这么个概念,它是相对于DOM1来讲的) DHTML(动态HTML)
DOM是独立于JS之外的一个API,目的为了跨语言操作标记语言(主要是XML)应运而生的一种技术
DOM Core(DOM1):解决的文档的层次结构和增删改查的一些方法属性
DOM2 有一部分是实现更好的事件的解决方案
DOM3
document.body.form;
document.forms;
document.anchors;
document.all;
document.all["div1"]
document.onclick;
var ele=document.getElementById("div1");
function fn1(){alert(1);}
function fn2(){alert(2);}
var n=0;
//如果点击超过2次,则从事件移除些方法
function fn3(){
n++;
if(n==2){
}
alert(3);}
function fn4(){alert(4);}
ele.onclick=fn1;
ele.onclick=function(){fn1();fn2();fn3();fn4();}
//DOM2级事件的方法
EventTarget.prototype.addEventListener;
EventTarget.prototype.removeEventListener;
//DOM2级事件中新增加的事件类型
document.addEventListener("DOMContentLoaded",fn2,false);
//文档的中标签已经加载并解析(标签已经在网页上显示了)就触发些事件,至于外链的图片、样式、JS是否加载或运行,跟这个事件无关。
$(document).ready(function(e) {
//"DOMContentLoaded"
fn1
});
//$的参数如果是一个function,则表示文档内容加载完成之后运行此方法,也就是$(document).ready()这个事件,其实就是"DOMContentLoaded"这个事件
$(fn1);//这个表示内容加载完成之后,触发fn2这个方法,相当于下面
$(document).ready(fn2);
//以下
$("#div1").click(fn1);
$("#div1").click(fn2);
ele.addEventListener("click",fn1,false);
ele.addEventListener("click",fn2,false);
//浏览器的所有资源都已完成加载(当然,会有加载失败的:超时),触发onload事件
window.onload;
for(var i=0;true;i++){
console.log(i);
}
document.addEventListener("DOMContentLoaded",function(){alert("ContentLoaded");},false)
dom二级事件兼容问题
var ele=document.getElementById("div1");
function fn1(){alert(1);}
function fn2(){alert(2);}
var n=0;
//如果点击超过2次,则从事件移这个方法
function fn3(){
n++;
if(n==2){//第二次执行的时候执行移除,到第三次的时候生效
this.removeEventListener("click",fn3,false);
}
alert(3);}
function fn4(){alert(4);}
ele.addEventListener("click",fn1,false);//第三个参数是指:是否在捕获阶段绑定此方法
ele.addEventListener("click",fn2,false);
ele.addEventListener("click",fn3,false);
ele.addEventListener("click",fn4,false);
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<title>无标题文档</title>
<style type="text/css">
#div1{ height:100px; background:red;}
</style>
</head>
<body>
<div id="div1">div1</div>
</body>
</html>
<script>
var ele=document.getElementById("div1");
function fn1(){alert(1);}
function fn2(){alert(2);}
var n=0;
//如果点击超过2次,则从事件移这个方法
function fn3(){
n++;
if(n==2){//第二次执行的时候执行移除,到第三次的时候生效
//this.removeEventListener("click",fn3,false);
unbind(ele,"click",fn3);
//不能把上一行代码中的ele换成this
}
alert(3);}
function fn4(){alert(4);}
function fn5(){alert(5);}
function fn6(){alert(6);}
function fn7(){alert(7);}
function fn8(){alert(8);}
function fn9(){alert(9);}
function fn10(){alert(10);}
function fn11(){alert(11);}
function fn12(){alert(12);}
bind(ele,"click",fn1);
bind(ele,"click",fn2);
bind(ele,"click",fn3);
bind(ele,"click",fn4);
bind(ele,"click",fn5);
bind(ele,"click",fn6);
bind(ele,"click",fn7);
bind(ele,"click",fn8);
bind(ele,"click",fn9);
bind(ele,"click",fn10);
bind(ele,"click",fn11);
bind(ele,"click",fn12);
function bind(ele,type,handler){//handler直译为句柄,方法名,方法引用的意思
if(ele.addEventListener){
ele.addEventListener(type,handler,false);
}else if(ele.attachEvent){
ele.attachEvent("on"+type,handler);
}
}
function unbind(ele,type,handler){
if(ele.removeEventListener){
ele.removeEventListener(type,handler,false);
}else if(ele.detachEvent){
ele.detachEvent("on"+type,handler);
}
}
</script>
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<title>无标题文档</title>
<style type="text/css">
#div1{ height:100px; background:red;}
</style>
</head>
<body>
<div id="div1">div1</div>
</body>
</html>
<script>
var ele=document.getElementById("div1");
function fn1(){
this.innerHTML="点过"+n;
alert(1);}
function fn2(){alert(2);}
var n=0;
//如果点击超过2次,则从事件移这个方法
function fn3(){
n++;
if(n==2){//第二次执行的时候执行移除,到第三次的时候生效
//this.removeEventListener("click",fn3,false);
unbind(this,"click",fn3);//
unbind(this,"click",fn2);
//不能把上一行代码中的ele换成this
//执行bind的时候,第一次fnTemp是fn1的变形
// 第二次fnTemp是fn2的变形
// 第三次fnTemp是fn3的变形
}
alert(3);}
function fn4(){alert(4);}
function fn5(){alert(5);}
function fn6(){alert(6);}
function fn7(){alert(7);}
function fn8(){alert(8);}
function fn9(){alert(9);}
function fn10(){alert(10);}
function fn11(){alert(11);}
function fn12(){alert(12);}
bind(ele,"click",fn1);
bind(ele,"click",fn2);
bind(ele,"click",fn3);
/*bind(ele,"click",fn4);
bind(ele,"click",fn5);
bind(ele,"click",fn6);
bind(ele,"click",fn7);
bind(ele,"click",fn8);
bind(ele,"click",fn9);
bind(ele,"click",fn10);
bind(ele,"click",fn11);
bind(ele,"click",fn12);*/
var fnTemp=null;
function bind(ele,type,handler){//handler直译为句柄,方法名,方法引用的意思
if(ele.addEventListener){
ele.addEventListener(type,handler,false);
}else if(ele.attachEvent){
//1、事件触发的时候handler方法执行
//2、让handler方法里的this指向ele
//记好一个原则:如果是解决this关键字的指向,则记好用call或apply方法
//以下的处理方式已经就可以实现让事件触发的时候,handler里的this指向ele了。如果就是解决仅仅是解决this关键字关键,已经就解决了
//即可以把fnTemp保存下来,还要保证fnTemp的安全,还要把多次变形得成的fnTemp都可以保存下来,并且在unbind里还可以识别出来当前这个fnTemp是由那个方法变形而来
//ele.abindclick=[];//自定义属性
//if(!ele.abindclick){
/*ele[handler]
ele[fn1]
ele["fn1"]
fn1=function(){};
fn2=function(){};*/
if(!ele["abind"+type]){
//这个自定义属性的命名规则是:abind是属性的前缀,click是属性的区分符
//ele.click
//为什么要用click来命名呢?把绑定在不同事件类型上的方法,以事件类型做为命名的依据来定义不同的数组,来保存不同的事件上的方法。
//但是我们又不能直接用事件类型作属性,容易和系统属性引起冲突,所以才在它前面加个前缀(为了让属性名变长,降低冲突的机率)
//ele[type]=[];
ele["abind"+type]=[];
}
var fnTemp=function(){handler.call(ele);};
fnTemp.photo=handler;//photo"照片",保存着它原来的面貌
ele["abind"+type].push(fnTemp);
ele.attachEvent("on"+type,fnTemp);
}
}
function unbind(ele,type,handler){
if(ele.removeEventListener){
ele.removeEventListener(type,handler,false);
}else if(ele.detachEvent){
var a=ele["abind"+type];
//a里的第i项可能就是handler变形而来
//a[i]==handler
//现在需要一个机制,能识别出a[i]是由handler变形来的
if(a){
for(var i=0;i<a.length;i++){
if(a[i].photo==handler){
ele.detachEvent("on"+type,a[i]);
return;
}
}
}
//ele.detachEvent("on"+type,fnTemp);
}
}
</script>
实战 面向对象的拖拽功能开发
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<title>无标题文档</title>
<style type="text/css">
div{ width:100px; height:100px; position:absolute; background:green; top:100px; left:100px; cursor:move; -webkit-user-select:none;}
</style>
</head>
<body>
<div id="div1" style="left:0; top:0; background:red;"></div>
<div id="div2"><img src="" height="100" width="100"></div>
<div id="div3" style="top:200px; left:150px; background:blue;"></div>
</body>
</html>
<script src="event1.js"></script>
<script>
//面向对象的编程强在管理、拓展功能。强项不是逻辑
//在使用面向对象编程方式之前,先要确定设计原则:this关键字的问题。
//this要指向当前类的实例,无论是构造函数还是原型函数,this都要指是指向类的实例。
//这一点会和事件原则中this冲突,如果存在冲突,强制使this指向类的实例
//一但使用的面向对象,代码的可读性会变差。
//使用面向对象,要理解整个类的体系
function Drag(ele){//构造函数是初始化的作用
this.x=null;
this.y=null;
this.mx=null;
this.my=null;
this.ele=ele;//把被拖拽的元素保存到当前实例的ele属性上,以便其类上的其它函数能够访问。如果不把ele保存到this.ele上,其它方法无法访问这个私有变量ele。一个方法里定义的变量或形参,都是私有变量,其它的函数里无法访问;但如果我们把一个值保存到this的属性,则这个属性就成了公有变量
/*
function processThis(fn,obj){
//返回的新方法:让fn的功能不变,但是this被强制改变了
return function(e){fn.call(obj,e);this}
function fn1(){
this;
fn();
}
}
*/
this.DOWN=processThis(this.down,this);
//processThis会返回一个新的方法,这个新的方法里还是执行老的方法this.down,但是会让this.down里的this一定指向当前类的实例
this.MOVE=processThis(this.move,this);
this.UP=processThis(this.up,this);
on(ele,"mousedown",this.DOWN);
//以下是错误的绑定方式
//on(ele,"mousedown",this.down);//我们原则是:down方法无论在什么情况下里的this都指向类的实例this
}
Drag.prototype.down=function(e){
this.x=this.ele.offsetLeft;
this.y=this.ele.offsetTop;
this.mx=e.pageX;
this.my=e.pageY;
if(this.ele.setCapture){
this.ele.setCapture();
on(this.ele,"mousemove",this.MOVE);
on(this.ele,"mouseup",this.UP);
}else{
on(document,"mousemove",this.MOVE);
on(document,"mouseup",this.UP);
}
e.preventDefault();
//一定要注意的是:如果事件是用DOM2事件绑定方法来绑定的,那么阻止事件的默认行为一定要用e.preventDefault()这个方法
}
Drag.prototype.move=function(e){
this.ele.style.left=this.x+e.pageX-this.mx+"px";
this.ele.style.top=this.y+e.pageY-this.my+"px";
}
Drag.prototype.up=function(e){
if(this.ele.releaseCapture){
this.ele.releaseCapture();
off(this.ele,"mousemove",this.MOVE);
off(this.ele,"mouseup",this.UP);
}else{
off(document,"mousemove",this.MOVE);
off(document,"mouseup",this.UP);
}
}
var obj1=new Drag(div1);
//操作的主体,上下文,是ele这个dom元素;现在操作的主体是obj1这个对象,这个obj1中,承载了所有的和拖拽相关的信息(属性和方法)
new Drag(div2);
new Drag(div3);
</script>
网友评论