WEB前端最常見驅動方式就是事件了, 所有交互等等都是通過事件,前端的常見事件有:
UI事件; 焦點事件; 鼠標事件; 滾輪事件; 文本事件; 鍵盤事件; 變動事件;
現在網頁上有一個輸入框, 如果我們要對用戶輸入的字符串進行過濾, 或者是截獲用戶的輸入進行處理的話, 我們要腫么辦
同學們紛紛舉手說:“老師,我知道,是使用添加事件“,
老師也很欣慰地點了點頭, 這群家伙真的是越來越聰明了,
老師又問了”如果要取消用戶的輸入怎么辦了“,
坐在最前排眼睛最小的同學急忙說”ev.preventDefault(),ev.returnValue = false;"
老師又說“不錯啊,都學會搶答了啊, 我褲子都脫了, 你就答這個2?”
過了一秒鐘, 又一位同學主動跑到黑板這邊寫了如下的代碼:
<!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事件,然后通過這個事件的回調對用戶的輸入進行處理";
如果在事件里面的代碼多了, 我們又可以把事件的代碼單獨取出來作為一個函數:
<!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
文章列表