JavaScript学习记录-脚本模型事件绑定

事件绑定分为两种:

  1. 传统事件绑定(内联模型,脚本模型)
  2.  现代事件绑定(DOM2级模型)。现代事件绑定在传统绑定上提供了更强大更方便的功能。

传统事件绑定的历史问题

传统事件绑定中内联模型基本很少使用不必了解。所谓脚本模型就是将一个函数赋值给一个事件处理函数。

<script>
    window.onload=function(){
        alert("Bert");
    }
</script>

打开网页会弹出提示框“Bert”。这是最常见也是最基本的事件绑定,但是存在很多问题

问题一

一般HTML文档中会引入多个JS文件,按顺序引入时对相同元素进行操作时会发生冲突,或者两个<script>代码中不同操作也会有一样的问题。譬如,上述的例子中在第一个<script>下增加一个相同的<script>弹出的信息为“Tom”,最终效果会发现打开网页会弹出提示框“Tom”,之前的<script>代码被覆盖了。

解决问题一

正因为第一个要执行的时间会失效,所以需要增加一个判断之前是否有window.onload这样一个事件,并且创建一个“保存器”用来存储第一个会失效的事件,之后再第二个执行事件中去调用这个判断来执行第一个事件。说的自己都绕了,还是代码展示形象一些。

<script>
    window.onload=function(){
        alert("Bert");
    }
    if(typeof window.onload=="function"){
        var saved=null;
        saved=window.onload;
    }
</script>
<script>
    window.onload=function(){
        if(saved)   saved();
        alert("Tom");
    }
</script>

saved就是window.onload,saved()相当于window.onload(),但是window.onload()是不能执行的,所以saved()相当于window.οnlοad=function(){}。增加一个这样判断之后,在页面中可以正常的先弹出“Bert”,再弹出“Tom”。

问题二

这个问题是涉及到事件切换器,首先来看一下事件切换器,

结构和JS:

<div id="test">测试</div>

<script>
    function toRed(){
        this.className="red";
        this.onclick=toBlue
    }
    function toBlue(){
        this.className="blue";
        this.onclick=toRed;
    }
    var box=document.getElementById("test");
    box.onclick=toRed;
</script>

CSS:

.red{
    width: 50px;
    height: 80px;
    line-height: 80px;
    color: blue;
    background-color: red;
}
.blue{
    width: 80px;
    height: 50px;
    line-height: 50px;
    color: red;
    background-color: blue;
}

这最终的结果就会在点击“测试”区域时,该区域会在“red”样式和“blue”样式之间来回切换。

首先,当在切换颜色事件之前想要增加一个弹窗时,会发现点击之后没有弹窗,因为被之后的改变颜色事件覆盖了,这也就是之前提到的第一个的覆盖问题

var box=document.getElementById("test");
box.onclick=function(){
    alert("开始事件切换咯!")
}
box.onclick=toRed;

如果想要解决上述问题,除了解决问题一提供的麻烦办法之外,还可以将两个事件包含在一个匿名函数中,但这就带来了第二个问题,this的指向问题

var box=document.getElementById("test");
box.onclick=function(){
    alert("开始事件切换咯!")
    toBlue();
}

但这时就只会出现弹窗而不会改变颜色,是因为通过匿名函数执行某一函数,里面的this就跳出了作用域,即代表window。若解决this指向问题可通过call来传递this。

toBlue.call(this);

最后,this指向问题解决了又带来了新问题,弹窗只弹出一次的问题。跳转到“toBlue”函数,其中的onclick改变成红色事件又会覆盖弹窗事件。

解决问题二

综上问题二中的诸多问题,可通过创建一个自定义的事件处理函数,来解决问题。添加事件函数,obj相当于window,type相当于onload,fn相当于functio(){}。

function addEvent(obj,type,fn){
    var saved=null;                             //用于保存上一个事件
    if(typeof obj["on"+type]=="function"){      //判断事件是否存在
        saved=obj["on"+type];                   //保存上一个事件
    }
    obj["on"+type]=function(){
        if(saved)   saved();
        fn.call(this);  //把this传递进去
    };
}

addEvent(window,"load",function(){
    var box=document.getElementById("test");
    addEvent(box,"click",function(){
        alert("改变颜色咯!");
    });
    addEvent(box,"click",toBlue);
});

function toRed(){
    this.className="red";
    addEvent(this,"click",toBlue);
}
function toBlue(){
    this.className="blue";
    addEvent(this,"click",toRed);
}

就此,可以实现点击一次出现一次弹窗,改变颜色。但是当你单击很多很多次切换后,浏览器直接卡死,或者弹出一个错误:too much recursion(太多的递归)。主要的原因是,每次切换事件的时候,都保存下来,没有把无用的移除,导致越积越多,最后卡死。可以添加一个删除事件处理函数来解决。

function removeEvent(obj, type) {
	if (obj['on'] + type) obj['on' + type] = null; 		//删除事件处理函数
}

function toRed(){
    this.className="red";
    removeEvent(this,"click");
    addEvent(this,"click",toBlue);
}
function toBlue(){
    this.className="blue";
    removeEvent(this,"click");
    addEvent(this,"click",toRed);
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值