观察者模式又叫作发布订阅者模式(Publish/Subscribe),它可让多个观察者对象同时监听某一个主题对象,这个主题对象的状态变化时会通知全部的订阅者,使得它们可以作出反应。JS的事件模型就是一种观察者模式的体现,当对应的事件被触发时,监听该事件的全部监听函数都会被调用。jquery
下面是用JS实现的一个观察者模式的代码:浏览器
var events = (function() { var topics = {}; return { publish: function(topic, info) { console.log('publish a topic:' + topic); if (topics.hasOwnProperty(topic)) { topics[topic].forEach(function(handler) { handler(info ? info : {}); }) } }, subscribe: function(topic, handler) { console.log('subscribe an topic:' + topic); if (!topics.hasOwnProperty(topic)) { topics[topic] = []; } topics[topic].push(handler); }, remove: function(topic, handler) { if (!topics.hasOwnProperty(topic)) { return; } var handlerIndex = -1; topics[topic].forEach(function(element, index) { if (element === handler) { handlerIndex = index; } }); if (handlerIndex >= 0) { topics[topic].splice(handlerIndex, 1); } }, removeAll: function(topic) { console.log('remove all the handler on the topic:' + topic); if (topics.hasOwnProperty(topic)) { topics[topic].length = 0; } } } })();
使用事例:app
//主题监听函数 var handler = function(info) { console.log(info); } //订阅hello主题 events.subscribe('hello', handler); //发布hello主题 events.publish('hello', 'hello world');
事件是与浏览器或文档交互的瞬间,如点击按钮,填写表格等,它是JS与HTML之间交互的桥梁。DOM是树形结构,若是同时给父子节点都绑定事件时,当触发子节点的时候,这两个事件的发生顺序如何决定?这就涉及到事件流的概念,它描述的是页面中接受事件的顺序。dom
事件流有两种:函数
事件冒泡(Event Capturing):spa
是一种从下往上的传播方式。事件最开始由最具体的元素(文档中嵌套层次最深的那个节点接受, 也就是DOM最低层的子节点), 而后逐渐向上传播到最不具体的那个节点,也就是DOM中最高层的父节点。代理
事件捕获(Event Bubbling):code
与事件冒泡相反。事件最开始由不太具体的节点最先接受事件, 而最具体的节点最后接受事件。
事件模型
DOM0级模型
又称为原始事件模型,在该模型中,事件不会传播,即没有事件流的概念。事件绑定监听函数比较简单, 有两种方式:对象
HTML代码中直接绑定:接口
<input type="button" onclick="fun()">
经过JS代码指定属性值:
var btn = document.getElementById('.btn'); btn.onclick = fun;
移除监听函数:
btn.onclick = null;
这种方式全部浏览器都兼容,可是逻辑与显示并无分离。
IE事件模型共有两个过程:
attachEvent(eventType, handler)
事件移除监听函数的方式以下:
detachEvent(eventType, handler)
参数说明:
eventType指定事件类型(注意加on)
handler是事件处理函数
Example:
var btn = document.getElementById('.btn'); btn.attachEvent(‘onclick’, showMessage); btn.detachEvent(‘onclick’, showMessage);
属于W3C标准模型,现代浏览器(除IE6-8以外的浏览器)都支持该模型。在该事件模型中,一次事件共有三个过程:
addEventListener(eventType, handler, useCapture)
事件移除监听函数的方式以下:
removeEventListener(eventType, handler, useCapture)
Example:
var btn = document.getElementById('.btn'); btn.addEventListener(‘click’, showMessage, false); btn.removeEventListener(‘click’, showMessage, false);
参数说明:
eventType指定事件类型(不要加on)
handler是事件处理函数
useCapture是一个boolean用于指定是否在捕获阶段进行处理,通常设置为false与IE浏览器保持一致。
事件对象
当一个事件被触发时,会建立一个事件对象(Event Object), 这个对象里面包含了与该事件相关的属性或者方法。该对象会做为第一个参数传递给监听函数。
经常使用属性:
IE事件模型中的事件对象经常使用属性:
因为事件模型的差别以及Event对象的不一样,为了达到兼容各个浏览器的目的,咱们能够增长一个Event Wrapper, 它对各个浏览器应当提供一致的事件操做接口。
var eventUtils={ // 添加句柄 addHandler:function(element,type,handler){ if(element.addEventListener){ element.addEventListener(type,handler,false); }else if(element.attachEvent){ element.attachEvent('on'+type,handler); }else{ element['on'+type]=handler; } }, // 删除句柄 removeHandler:function(element,type,handler){ if(element.removeEventListener){ element.removeEventListener(type,handler,false); }else if(element.detachEvent){ element.detachEvent('on'+type,handler); }else{ element['on'+type]=null; } }, //获取事件对象 //IE模型中event是一个全局惟一的对象绑定在window对象上 getEvent:function(event){ return event?event:window.event; }, //获取类型 getType:function(event){ return event.type; }, getElement:function(event){ return event.target || event.srcElement; }, //阻止默认事件 preventDefault:function(event){ if(event.preventDefault){ event.preventDefault(); }else{ event.returnValue=false; } }, //阻止冒泡 stopPropagation:function(event){ if(event.stopPropagation){ event.stopPropagation(); }else{ event.cancelBubble=true; } } }
事件在冒泡过程当中会上传到父节点,所以能够把子节点的监听函数定义在父节点上,由父节点的监听函数统一处理多个子元素的事件,这种方式称为事件代理(Event delegation)。
咱们有一个div元素,它包含三个按钮:
<div id="box"> <input type="button" value="按钮" id="btn"> <input type="button" value="按钮2" id="btn2"> <input type="button" value="按钮3" id="btn3"> </div>
咱们能够在父节点上一次性的为全部子节点注册监听函数:
var box = document.getElementById('box'); box.addEventListener('click', function(event) { if (event.target.tagName.toLowerCase() === 'input') { // some code } });
JS中已经内置了不少事件,如click, mouseover等等,可是内置事件毕竟有限,有时候咱们想本身定义一些事件,例如三连击,threeclick。如何实现自定义事件呢?
var event = new Event('threeclick', {"bubbles":true, "cancelable":false});
target.addEventListener('threeclick', hello, false);
target.dispatchEvent(event);
JQuery解决的一个主要问题就是浏览器的兼容问题,它有本身的事件模型实现方式。它主要有如下特性: