WEB前端最多見驅動方式就是事件了, 全部交互等等都是經過事件,前端的常見事件有:html
UI事件; 焦點事件; 鼠標事件; 滾輪事件; 文本事件; 鍵盤事件; 變更事件;
如今網頁上有一個輸入框, 若是咱們要對用戶輸入的字符串進行過濾, 或者是截獲用戶的輸入進行處理的話, 咱們要腫麼辦 前端
同窗們紛紛舉手說:「老師,我知道,是使用添加事件「,設計模式
老師也很欣慰地點了點頭, 這羣傢伙真的是愈來愈聰明瞭,app
老師又問了」若是要取消用戶的輸入怎麼辦了「,模塊化
坐在最前排眼睛最小的同窗急忙說」ev.preventDefault(),ev.returnValue = false;"函數
老師又說「不錯啊,都學會搶答了啊, 我褲子都脫了, 你就答這個2?」 post
過了一秒鐘, 又一位同窗主動跑到黑板這邊寫了以下的代碼:ui
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> <title>MAKER</title> </head> <body> <div id="log"> Log: </div> <input id="text">data</input> <script> window.onload = init; if(console&&console.log) { var originalLog = console.log; var log = document.getElementById("log"); console.log = function(arg) { var eDiv = document.createElement("div"); eDiv.innerHTML = typeof arg === "string" ? arg : arg.toString(); log.appendChild( eDiv ); originalLog.apply(console, arguments); }; }; function init () { var eText = document.getElementById("text"); eText.addEventListener("keypress", function( ev ) { //邏輯所有在這裏面, 很簡單吧; var code = ev.which = ev.which || ev.keyCode || ev.charCode; console.log( code ); if(code > 80) { console.log("code>80"); }; if(ev.shiftKey === true) { console.log("shift key is pressed!") } }); }; </script> </body> </html>
"哎喲,不錯哦,這個*x"老師說道:"這個就是咱們最經常使用的方法, 直接爲元素綁定了keypress事件,而後經過這個事件的回調對用戶的輸入進行處理";this
若是在事件裏面的代碼多了, 咱們又能夠把事件的代碼單獨取出來做爲一個函數:url
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> <title>MAKER</title> </head> <body> <div id="log"> Log: </div> <input id="text">data</input> <script> window.onload = init; if(console&&console.log) { var originalLog = console.log; var log = document.getElementById("log"); console.log = function(arg) { var eDiv = document.createElement("div"); eDiv.innerHTML = typeof arg === "string" ? arg : arg.toString(); log.appendChild( eDiv ); originalLog.apply(console, arguments); }; }; var 我是事件 = function(ev) { //邏輯所有在這裏面, 很簡單吧; var code = ev.which = ev.which || ev.keyCode || ev.charCode; console.log( code ); if(code > 80) { console.log("code>80"); }; if(ev.shiftKey === true) { console.log("shift key is pressed!") }; }; function init () { var eText = document.getElementById("text"); eText.addEventListener("keypress", function( ev ) { 我是事件(ev); }); }; </script> </body> </html>
看起來清楚多了是吧, 可是在大的項目中(我說的是若是哇), 咱們想要充分解耦代碼, 能夠事件裏面的代碼所有從新分開:
函數1 :console.log( code );
函數2:
if(code > 80) {
console.log("code>80");
};
函數3:
if(ev.shiftKey === true) { console.log("shift key is pressed!") };
好吧,如今問題來了....
如今有要上菜了哇, JS中的自定義事件, 充分利用JS的事件機制,
抄自百科:對於自定義事件最須要了解的一點是,您的代碼必須致使這些事件發生。這些事件不會爲響應用戶或系統的動做而自動發生,即便可以編寫致使事件確實以這種方式發生的代碼也不例外。包含自定義事件的類模塊還必須包括一個喚起事件的公有方法。這個方法經過調用 RaiseEvent 語句並傳入爲事件定義的任何參數來喚起事件。這些參數按順序傳入爲響應事件而運行的事件過程當中
自定義事件就是一種的設計模式,好比訂閱者發佈者模式, 觀察者模式等等, 都是自定義事件基礎上的模式(我的觀點, 勿拍磚), 關鍵是不少大神寫代碼喜歡用這一種模式寫, 那麼咱們也能夠借鑑, 這樣就夠了;
咱們如今把上面那段經過自定義事件的方式寫出來:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> <title>MAKER</title> </head> <body> <script> //d爲目標對象, b爲一個函數對象; var __extends = this.__extends || function (d, b) { //繼承了靜態屬性 for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; function __() { this.constructor = d; } //繼承了原型 __.prototype = b.prototype; d.prototype = new __(); }; var EventEmitter = (function () { function EventEmitter() { this._events = {}; } EventEmitter.prototype.emit = function (type) { var _this = this; var args = []; for (var _i = 0; _i < (arguments.length - 1); _i++) { args[_i] = arguments[_i + 1]; } // If there is no 'error' event listener then throw. if (type === 'error') { if (!this._events[type] || (Array.isArray(this._events[type]) && !this._events[type].length)) { if (args[0] instanceof Error) { throw args[0]; } else { throw new Error("Uncaught, unspecified 'error' event."); } return false; } } if (this._events[type]) { this._events[type].forEach(function (handler) { return handler.apply(_this, args); }); return true; } return false; }; EventEmitter.prototype.addListener = function (type, listener) { if ('function' !== typeof listener) { throw new Error('addListener only takes instances of Function'); } var events = this._events; var listeners = events[type]; if (!listeners) listeners = events[type] = []; else if (listeners.indexOf(listener) >= 0) return this; listeners.push(listener); return this; }; EventEmitter.prototype.removeListener = function (type, listener) { var events = this._events; if (!events[type]) return this; var listeners = events[type]; var i = listeners.indexOf(listener); if (i >= 0) listeners.splice(i, 1); return this; }; return EventEmitter; })(); //寫一個小的案例, 爲了充分解耦代碼, 咱們能夠把代碼經過自定義的事件分紅幾個模塊; </script> <input id="text">data</input> <script> window.onload = init; function init () { var TextEvent = (function(Emiter) { __extends(TextEvent, Emiter); function TextEvent() { Emiter.apply(this); }; return TextEvent; }.call(TextEvent,EventEmitter)); //建立了這個實例; var textEvent = new TextEvent(); //爲實例添加自定義事件; textEvent.addListener("keypress", function preventDefault(ev) { ev.preventDefault(); }); //爲實例添加自定義事件; textEvent.addListener("keypress", function(ev) { var code = ev.which = ev.which || ev.keyCode || ev.charCode; console.log( code ); }); //爲實例添加自定義事件; textEvent.addListener("keypress", function(ev) { var code = ev.which = ev.which || ev.keyCode || ev.charCode; if(code > 80) { console.log("code>80"); }; }); //爲實例添加自定義事件; textEvent.addListener("keypress", function(ev) { var code = ev.which = ev.which || ev.keyCode || ev.charCode; if(ev.shiftKey === true) { console.log("shift key is pressed!") }; }); document.getElementById("text").addEventListener("keypress", function( ev ) { textEvent.emit("keypress",ev) }); }; </script> </body> </html>
樓主你他媽在逗我? 這麼多
實現要懂JS的繼承:
//d爲目標對象, b爲一個函數對象; var __extends = this.__extends || function (d, b) { //繼承了靜態屬性 for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; function __() { this.constructor = d; } //繼承了原型 __.prototype = b.prototype; d.prototype = new __(); };
其次呢, 自定義事件的代碼要懂, 不少地方都有用到;
var EventEmitter = (function () { function EventEmitter() { this._events = {}; } EventEmitter.prototype.emit = function (type) { var _this = this; var args = []; for (var _i = 0; _i < (arguments.length - 1); _i++) { args[_i] = arguments[_i + 1]; } // If there is no 'error' event listener then throw. if (type === 'error') { if (!this._events[type] || (Array.isArray(this._events[type]) && !this._events[type].length)) { if (args[0] instanceof Error) { throw args[0]; } else { throw new Error("Uncaught, unspecified 'error' event."); } return false; } } if (this._events[type]) { this._events[type].forEach(function (handler) { return handler.apply(_this, args); }); return true; } return false; }; EventEmitter.prototype.addListener = function (type, listener) { if ('function' !== typeof listener) { throw new Error('addListener only takes instances of Function'); } var events = this._events; var listeners = events[type]; if (!listeners) listeners = events[type] = []; else if (listeners.indexOf(listener) >= 0) return this; listeners.push(listener); return this; }; EventEmitter.prototype.removeListener = function (type, listener) { var events = this._events; if (!events[type]) return this; var listeners = events[type]; var i = listeners.indexOf(listener); if (i >= 0) listeners.splice(i, 1); return this; }; return EventEmitter; })();
最後經過組合繼承, 實現了一個自定義事件類方法:
var TextEvent = (function(Emiter) { __extends(TextEvent, Emiter); function TextEvent() { Emiter.apply(this); }; return TextEvent; }.call(TextEvent,EventEmitter));
咱們經過實例化TextEvent, 爲這個實例添加自定義的方法;
在onkeypress的事件回調觸發自定義事件textEvent.emit("keypress",ev), 最後的最後只要爲textEvent綁定自定義事件便可,這樣作的優點就是: 咱們能夠經過removeListener去除事件, 事件函數也能夠直接複用, 很靈活;
D