js事件模型3

JavaScript事件列表
事件 解说
一般事件 onclick 鼠标点击时触发此事件
ondblclick 鼠标双击时触发此事件
onmousedown 按下鼠标时触发此事件
onmouseup 鼠标按下后松开鼠标时触发此事件
onmouseover 当鼠标移动到某对象范围的上方时触发此事件
onmousemove 鼠标移动时触发此事件
onmouseout 当鼠标离开某对象范围时触发此事件
onkeypress 当键盘上的某个键被按下并且释放时触发此事件.
onkeydown 当键盘上某个按键被按下时触发此事件
onkeyup 当键盘上某个按键被按放开时触发此事件
页面相关事件 onabort 图片在下载时被用户中断
onbeforeunload 当前页面的内容将要被改变时触发此事件
onerror 出现错误时触发此事件
onload 页面内容完成时触发此事件
onmove 浏览器的窗口被移动时触发此事件
onresize 当浏览器的窗口大小被改变时触发此事件
onscroll 浏览器的滚动条位置发生变化时触发此事件
onstop 浏览器的停止按钮被按下时触发此事件或者正在下载的文件被中断
oncontextmenu 当弹出右键上下文菜单时发生
onunload 当前页面将被改变时触发此事件
表单相关事件 onblur 当前元素失去焦点时触发此事件
onchange 当前元素失去焦点并且元素的内容发生改变而触发此事件
onfocus 当某个元素获得焦点时触发此事件
onreset 当表单中RESET的属性被激发时触发此事件
onsubmit 一个表单被递交时触发此事件


鼠标 / 键盘属性
altKey
返回当事件被触发时,"ALT" 是否被按下。
button
返回当事件被触发时,哪个鼠标按钮被点击。
clientX
返回当事件被触发时,鼠标指针的水平坐标。
clientY
返回当事件被触发时,鼠标指针的垂直坐标。
ctrlKey
返回当事件被触发时,"CTRL" 键是否被按下。
metaKey
返回当事件被触发时,"meta" 键是否被按下。
relatedTarget
返回与事件的目标节点相关的节点。
screenX
返回当某个事件被触发时,鼠标指针的水平坐标。
screenY
返回当某个事件被触发时,鼠标指针的垂直坐标。
shiftKey
返回当事件被触发时,"SHIFT" 键是否被按下。

IE 属性

cancelBubble
如果事件句柄想阻止事件传播到包容对象,必须把该属性设为 true。
fromElement
对于 mouseover 和 mouseout 事件,fromElement 引用移出鼠标的元素。
keyCode
对于 keypress 事件,该属性声明了被敲击的键生成的 Unicode 字符码。对于 keydown 和 keyup 事件,它指定了被敲击的键的虚拟键盘码。虚拟键盘码可能和使用的键盘的布局相关。
offsetX,offsetY
发生事件的地点在事件源元素的坐标系统中的 x 坐标和 y 坐标。
returnValue
如果设置了该属性,它的值比事件句柄的返回值优先级高。把这个属性设置为 fasle,可以取消发生事件的源元素的默认动作。
srcElement
对于生成事件的 Window 对象、Document 对象或 Element 对象的引用。
toElement
对于 mouseover 和 mouseout 事件,该属性引用移入鼠标的元素。
x,y 事件发生的位置的 x 坐标和 y 坐标,它们相对于用CSS动态定位的最内层包容元素。

标准 Event 属性

下面列出了 2 级 DOM 事件标准定义的属性
bubbles
返回布尔值,指示事件是否是起泡事件类型。
cancelable
返回布尔值,指示事件是否可拥可取消的默认动作。
currentTarget
返回其事件监听器触发该事件的元素。
eventPhase
返回事件传播的当前阶段。
target
返回触发此事件的元素(事件的目标节点)。
timeStamp
返回事件生成的日期和时间。
type
返回当前 Event 对象表示的事件的名称。

标准 Event 方法

下面列出了 2 级 DOM 事件标准定义的方法。IE 的事件模型不支持这些方法:
initEvent()
初始化新创建的 Event 对象的属性。
preventDefault()
通知浏览器不要执行与事件关联的默认动作。
stopPropagation()
不再派发事件。


Event对象

//W3C DOM把事件对象作为事件处理函数的第一个参数传入进去
    document.onclick = function (evt) {//这样,事件对象只能在对应的事件处理函数内部可以访问到
        alert(evt);
    };
    //IE将事件对象作为window对象的一个属性(相当于全局变量)
    //貌似全局对象,但是只有是事件发生时才能够访问
    alert(window.event);//null
    window.onload = function () {
        alert(window.event);
    };```
#阻止事件发生时浏览器的默认行为
```javascript
    document.onclick = function (evt) {
        evt = evt || window.event;
        var target = evt.target || evt.srcElement;
        if (!target) {
            return;
        }
        if (target.tagName=="A" && target.href) {
            //使用传统的方法取消事件默认行为必须使用return false
            //但使用了return ,函数便终止了运行,可以使用事件对象来取消
            if (window.event) {//IE
                window.event.returnValue = false;
            } else {
                evt.preventDefault();
            }
            window.open(target.href,"newWindow");
            //这样让所有的链接在新窗口打开
        }
    };
    ```
冒泡事件流 从当前节点向根节点冒泡
捕获事件流 从根节点向触发节点传递事件
```javascript
    function addEvent(obj,evtype,fn,useCapture) {
        if (obj.addEventListener) {//useCapture true 捕获阶段执行
            obj.addEventListener(evtype,fn,useCapture);
        } else {
            obj.attachEvent("on"+evtype,fn);//IE不支持事件捕获
        } else {
            obj["on"+evtype]=fn;//事实上这种情况不会存在
        }
    }
    function delEvent(obj,evtype,fn,useCapture) {
        if (obj.removeEventListener) {
            obj.removeEventListener(evtype,fn,useCapture);
        } else {
            obj.detachEvent("on"+evtype,fn);
        } else {
            obj["on"+evtype]=null;
        }
    }

其它兼容性问题:IE不支持事件捕获?很抱歉,这个没有办法解决!但IE的attach方法有个问题,就是使用attachEvent时在事件处理函数内部,this指向了window,而不是obj!####

****解决方案

function addEvent(obj,evtype,fn,useCapture) {
        if (obj.addEventListener) {
            obj.addEventListener(evtype,fn,useCapture);
        } else {
            obj.attachEvent("on"+evtype,function () {
                fn.call(obj);
            });
        } else {
            obj["on"+evtype]=fn;//事实上这种情况不会存在
        }
    }

但IE的attachEvent方法有另外一个问题,同一个函数可以被注册到同一个对象同一个事件上多次,解决方法:抛弃IE的 attachEvent方法吧!IE下的attachEvent方法不支持捕获,和传统事件注册没多大区别(除了能绑定多个事件处理函数),并且IE的 attachEvent方法存在内存泄漏问题

****addEvent,delEvent现代版,暂时没看懂

    function addEvent(obj,evtype,fn,useCapture) {
        if (obj.addEventListener) {//优先考虑W3C事件注册方案
            obj.addEventListener(evtype,fn,!!useCapture);
        } else {//当不支持addEventListener时(IE),由于IE同时也不支持捕获,所以不如使用传统事件绑定
            if (!fn.__EventID) {fn.__EventID = addEvent.__EventHandlesCounter++;}
            //为每个事件处理函数分配一个唯一的ID
            
            if (!obj.__EventHandles) {obj.__EventHandles={};}
            //__EventHandles属性用来保存所有事件处理函数的引用
            
            //按事件类型分类
            if (!obj.__EventHandles[evtype]) {//第一次注册某事件时
                obj.__EventHandles[evtype]={};
                if (obj["on"+evtype]) {//以前曾用传统方式注册过事件处理函数
                    (obj.__EventHandles[evtype][0]=obj["on"+evtype]).__EventID=0;//添加到预留的0位
                    //并且给原来的事件处理函数增加一个ID
                }
                obj["on"+evtype]=addEvent.execEventHandles;
                //当事件发生时,execEventHandles遍历表obj.__EventHandles[evtype]并执行其中的函数
            }
        }
    }
    addEvent.__EventHandlesCounter=1;//计数器,0位预留它用
    addEvent.execEventHandles = function (evt) {//遍历所有的事件处理函数并执行
        if (!this.__EventHandles) {return true;}
        evt = evt || window.event;
        var fns = this.__EventHandles[evt.type];
        for (var i in fns) {
                fns[i].call(this);
        }
    };
    function delEvent(obj,evtype,fn,useCapture) {
        if (obj.removeEventListener) {//先使用W3C的方法移除事件处理函数
            obj.removeEventListener(evtype,fn,!!useCapture);
        } else {
            if (obj.__EventHandles) {
                var fns = obj.__EventHandles[evtype];
                if (fns) {delete fns[fn.__EventID];}
            }
        }
    }

IE EVENT对象有些不兼容的地方,修改方式如下

    function fixEvent(evt) {
        if (!evt.target) {
            evt.target = evt.srcElement;
            evt.preventDefault = fixEvent.preventDefault;
            evt.stopPropagation = fixEvent.stopPropagation;
            if (evt.type == "mouseover") {
                evt.relatedTarget = evt.fromElement;
            } else if (evt.type =="mouseout") {
                evt.relatedTarget = evt.toElement;
            }
            evt.charCode =  (evt.type=="keypress")?evt.keyCode:0;
            evt.eventPhase = 2;//IE仅工作在冒泡阶段
            evt.timeStamp = (new Date()).getTime();//仅将其设为当前时间
        }
        return evt;
    }
    fixEvent.preventDefault =function () {
        this.returnValue = false;//这里的this指向了某个事件对象,而不是fixEvent
    };
    fixEvent.stopPropagation =function () {
        this.cancelBubble = true;
    };

fixEvent函数不是单独执行的,它必须有一个事件对象参数,而且只有事件发生时它才被执行!最好的方法是把它整合到addEvent函数的execEventHandles里面

    addEvent.execEventHandles = function (evt) {//遍历所有的事件处理函数并执行
        if (!this.__EventHandles) {return true;}
        evt = fixEvent(evt || window.event);//在这里对其进行标准化操作
        var fns = this.__EventHandles[evt.type];
        for (var i in fns) {
                fns[i].call(this,evt);//并且将其作为事件处理函数的第一个参数
                //这样在事件处理函数内部就可以使用统一的方法访问事件对象了
        }
    };

Load事件

使用JavaScript操纵DOM,必须等待DOM加载完毕才可以执行代码,但window.onload有个坏处,它非要等到页面中的所有图片 及视频加载完毕才会触发load事件。结果就是一些本来应该在打开时隐藏起来的元素,由于网络延迟,在页面打开时仍然会出现,然后又会突然消失,让用户觉 得莫名其妙。
大师们想出来的方法:

    function addLoadEvent(fn) {
        var init = function() {
            if (arguments.callee.done) return;
            arguments.callee.done = true;
            fn.apply(document,arguments);
        };
        //注册DOMContentLoaded事件,如果支持的话
        if (document.addEventListener) {
            document.addEventListener("DOMContentLoaded", init, false);
        }
        //但对于Safari,我们需要使用setInterval方法不断检测document.readyState
        //当为loaded或complete的时候表明DOM已经加载完毕
        if (/WebKit/i.test(navigator.userAgent)) {
            var _timer = setInterval(function() {
                if (/loaded|complete/.test(document.readyState)) {
                    clearInterval(_timer);
                    init();
                }
            },10);
        }
        //对于IE则使用条件注释,并使用script标签的defer属性
        //IE中可以给script标签添加一个defer(延迟)属性,这样,标签中的脚本只有当DOM加载完毕后才执行
        /*@cc_on @*/
        /*@if (@_win32)
        document.write("<script id=\"__ie_onload\" defer=\"defer\" src=\"javascript:void(0)\"><\/script>");
        var script = document.getElementById("__ie_onload");
        script.onreadystatechange = function() {
            if (this.readyState == "complete") {
                init();
            }
        };
        /*@end @*/
        return true;
     }
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 202,607评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,047评论 2 379
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 149,496评论 0 335
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,405评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,400评论 5 364
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,479评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,883评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,535评论 0 256
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,743评论 1 295
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,544评论 2 319
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,612评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,309评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,881评论 3 306
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,891评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,136评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,783评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,316评论 2 342

推荐阅读更多精彩内容

  • 事件流 IE和Netscape开发团队提出了完全相反的两种事件流的概念,事件冒泡流和事件捕获流。 事件冒泡 事件由...
    exialym阅读 921评论 0 9
  • 13.1 事件流 “DOM2级事件”规定事件流包括3个阶段:事件捕获阶段,处于目标阶段,事件冒泡阶段。事件捕获表示...
    Elevens_regret阅读 404评论 0 0
  • 之前写过一篇浏览器事件的相关操作和事件运行的原理——JavaScript浏览器事件解析。这一篇主要写一些常用的事件...
    faremax阅读 1,599评论 0 0
  • 总结: 鼠标事件 1.click与dbclick事件$ele.click()$ele.click(handler(...
    阿r阿r阅读 1,593评论 2 10
  • 婉约一词,始见于先秦古籍《国语·吴语》的“故婉约其辞”,欲诉还休、含蓄蕴藉,此为婉约之美,多用于论文学修辞。婉约二...
    泰迪熊的思念阅读 687评论 2 6