欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

利用Javascript實現一套自定義事件機制

 更新時間:2017年12月14日 11:07:24   作者:依韻  
隨著web技術發(fā)展,使用JavaScript自定義對象愈發(fā)頻繁,讓自己創(chuàng)建的對象也有事件機制,通過事件對外通信,能夠極大提高開發(fā)效率。下面這篇文章主要給大家介紹了關于利用Javascript實現一套自定義事件機制的相關資料,需要的朋友可以參考下。

前言

事件機制為我們的web開發(fā)提供了極大的方便,使得我們能在任意時候指定在什么操作時做什么操作、執(zhí)行什么樣的代碼。

如點擊事件,用戶點擊時觸發(fā);keydown、keyup事件,鍵盤按下、鍵盤彈起時觸發(fā);還有上傳控件中,文件加入前事件,上傳完成后事件。

由于在恰當的時機會有相應的事件觸發(fā),我們能為這些事件指定相應的處理函數,就能在原本的流程中插入各種各樣的個性化操作和處理,使得整個流程變得更加豐富。

諸如click、blur、focus等事件是原本的dom就直接提供的原生事件,而我們使用的一些其他控件所使用的各種事件則不是原生dom就有的,如上傳控件中通常都會有上傳開始和完成事件,那么這些事件都是如何實現的呢?

也想在自己的開發(fā)的控件中加入類似的事件機制該如何實現呢? 就讓我們來一探究竟。

事件應有的功能

在實現之前,我們首先來分析事件機制應該有的基本功能。

簡單來說,事件必須要提供以下幾種功能:

  • 綁定事件
  • 觸發(fā)事件
  • 取消綁定事件

前期準備

我們來觀察一下事件的一個特征,事件必定是屬于某個對象的。如:focus和blur事件是可獲取焦點的dom元素的,input事件是輸入框的,上傳開始和上傳成功則是上傳成功的。

也就是說,事件不是獨立存在的,它需要一個載體。那么我們怎么讓事件有一個載體呢?一種簡單的實現方案則是,將事件作為一個基類,在需要事件的地方繼承這個事件類即可。

我們將綁定事件、觸發(fā)事件、取消綁定事件分別命名為:on、fire、off,那么我們可以簡單寫出這個事件類:

function CustomEvent() {
 this._events = {};
}
CustomEvent.prototype = {
 constructor: CustomEvent,
 // 綁定事件
 on: function () {
 },
 // 觸發(fā)事件
 fire: function () {
 },
 // 取消綁定事件
 off: function () {
 }
};

事件綁定

首先來實現事件的綁定,事件綁定必須要指定事件的類型和事件的處理函數。

那么除此之外還需要什么呢?我們是自定義事件,不需要像原生事件一樣指定是冒泡階段觸發(fā)還是捕獲階段觸發(fā),也不需要像jQuery里一樣可以額外指定那些元素觸發(fā)。

而事件函數里面this一般都是當前實例,這個在某些情況下可能不適用,我們需要重新指定事件處理函數運行時的上下文環(huán)境。

因此確定事件綁定時三個參數分別為:事件類型、事件處理函數、事件處理函數執(zhí)行上下文。

那么事件綁定要干什么呢,其實很簡單,事件綁定只用將相應的事件名稱和事件處理函數記錄下來即可。

我的實現如下:

{
 /**
  * 綁定事件
  * 
  * @param {String} type 事件類型
  * @param {Function} fn 事件處理函數
  * @param {Object} scope 要為事件處理函數綁定的執(zhí)行上下文
  * @returns 當前實例對象
  */
 on: function (type, fn, scope) {
  if (type + '' !== type) {
   console && console.error && console.error('the first argument type is requird as string');
   return this;
  }
  if (typeof fn != 'function') {
   console && console.error && console.error('the second argument fn is requird as function');
   return this;
  }
  type = type.toLowerCase();

  if (!this._events[type]) {
   this._events[type] = [];
  }
  this._events[type].push(scope ? [fn, scope] : [fn]);
  return this;
 }
}

由于一種事件可以綁定多次,執(zhí)行時依次執(zhí)行,所有事件類型下的處理函數存儲使用的是數組。

事件觸發(fā)

事件觸發(fā)的基本功能就是去執(zhí)行用戶所綁定的事件,所以只用在事件觸發(fā)時去檢查有沒有指定的執(zhí)行函數,如果有則調用即可。

另外事件觸發(fā)實際就是用戶指定的處理函數執(zhí)行的過程,而能進行很多個性化操作也都是在用戶指定的事件處理函數中進行的,因此僅僅是執(zhí)行這個函數還不夠。還必須為當前函數提供必要的信息,如點擊事件中有當前被點擊的元素,鍵盤事件中有當前鍵的鍵碼,上傳開始和上傳完成中有當前文件的信息。

因此事件觸發(fā)時,事件處理函數的實參中必須包含當前事件的基本信息。

除此之外通過用戶在事件處理函數中的操作,可能需要調整之后的信息,如keydwon事件中用戶可以禁止此鍵的錄入,文件上傳前,用戶在事件中取消此文件的上傳或是修改一些文件信息。因此事件觸發(fā)函數應返回用戶修改后的事件對象。

我的實現如下:

{
 /**
  * 觸發(fā)事件
  * 
  * @param {String} type 觸發(fā)事件的名稱
  * @param {Object} data 要額外傳遞的數據,事件處理函數參數如下
  * event = {
   // 事件類型
   type: type,
   // 綁定的源,始終為當前實例對象
   origin: this,
   // 事件處理函數中的執(zhí)行上下文 為 this 或用戶指定的上下文對象
   scope :this/scope
   // 其他數據 為fire時傳遞的數據
  }
  * @returns 事件對象
  */
 fire: function (type, data) {
  type = type.toLowerCase();
  var eventArr = this._events[type];
  var fn,
   // event = {
   //  // 事件類型
   //  type: type,
   //  // 綁定的源
   //  origin: this,
   //  // scope 為 this 或用戶指定的上下文,
   //  // 其他數據 
   //  data: data,
   //  // 是否取消
   //  cancel: false
   // };
   // 上面對自定義參數的處理不便于使用 將相關屬性直接合并到事件參數中
   event = $.extend({
    // 事件類型
    type: type,
    // 綁定的源
    origin: this,
    // scope 為 this 或用戶指定的上下文,
    // 其他數據 
    // data: data,
    // 是否取消
    cancel: false
   }, data);
  if (!eventArr) {
   return event;
  }
  for (var i = 0, l = eventArr.length; i < l; ++i) {
   fn = eventArr[i][0];
   event.scope = eventArr[i][1] || this;
   fn.call(event.scope, event);
  }
  return event;
 }
}

上面實現中給事件處理函數的實參中必定包含以下信息:

  • type : 當前觸發(fā)的事件類型
  • origin : 當前事件綁定到的對象
  • scope : 事件處理函數的執(zhí)行上下文

此外不同事件在各種的觸發(fā)時可為此事件對象中加入各自不同的信息。

關于 Object.assign(target, ...sources) 是ES6中的一個方法,作用是將所有可枚舉屬性的值從一個或多個源對象復制到目標對象,并返回目標對象,類似于大家熟知的$.extend(target,..sources) 方法。

事件取消

事件取消中需要做的就是已經綁定的事件處理函數移除掉即可。

實現如下:

{
 /**
  * 取消綁定一個事件
  * 
  * @param {String} type 取消綁定的事件名稱
  * @param {Function} fn 要取消綁定的事件處理函數,不指定則移除當前事件類型下的全部處理函數
  * @returns 當前實例對象
  */
 off: function (type, fn) {
  type = type.toLowerCase();
  var eventArr = this._events[type];
  if (!eventArr || !eventArr.length) return this;
  if (!fn) {
   this._events[type] = eventArr = [];
  } else {
   for (var i = 0; i < eventArr.length; ++i) {
    if (fn === eventArr[i][0]) {
     eventArr.splice(i, 1);
     // 1、找到后不能立即 break 可能存在一個事件一個函數綁定多次的情況
     // 刪除后數組改變,下一個仍然需要遍歷處理!
     --i;
    }
   }
  }
  return this;
 }
}

此處實現類似原生的事件取消綁定,如果指定了事件處理函數則移除指定事件的指定處理函數,如果省略事件處理函數則移除當前事件類型下的所有事件處理函數。

僅觸發(fā)一次的事件

jQuery中有一個 one 方法,它所綁定的事件僅會執(zhí)行一次,此方法在一些特定情況下非常有用,不需要用戶手動取消綁定這個事件。

這里的實現也非常簡單,只用在觸發(fā)這個事件時取消綁定即可。

實現如下:

{
 /**
  * 綁定一個只執(zhí)行一次的事件
  * 
  * @param {String} type 事件類型
  * @param {Function} fn 事件處理函數
  * @param {Object} scope 要為事件處理函數綁定的執(zhí)行上下文
  * @returns 當前實例對象
  */
 one: function (type, fn, scope) {
  var that = this;
  function nfn() {
   // 執(zhí)行時 先取消綁定
   that.off(type, nfn);
   // 再執(zhí)行函數
   fn.apply(scope || that, arguments);
  }
  this.on(type, nfn, scope);
  return this;
 }
}

原理則是不把用戶指定的函數直接綁定上去,而是生成一個新的函數,并綁定,此函數執(zhí)行時會先取消綁定,再執(zhí)行用戶指定的處理函數。

基本雛形

到此,一套完整的事件機制就已經完成了,完整代碼如下:

function CustomEvent() {
 this._events = {};
}
CustomEvent.prototype = {
 constructor: CustomEvent,
 /**
  * 綁定事件
  * 
  * @param {String} type 事件類型
  * @param {Function} fn 事件處理函數
  * @param {Object} scope 要為事件處理函數綁定的執(zhí)行上下文
  * @returns 當前實例對象
  */
 on: function (type, fn, scope) {
  if (type + '' !== type) {
   console && console.error && console.error('the first argument type is requird as string');
   return this;
  }
  if (typeof fn != 'function') {
   console && console.error && console.error('the second argument fn is requird as function');
   return this;
  }
  type = type.toLowerCase();

  if (!this._events[type]) {
   this._events[type] = [];
  }
  this._events[type].push(scope ? [fn, scope] : [fn]);

  return this;
 },
 /**
  * 觸發(fā)事件
  * 
  * @param {String} type 觸發(fā)事件的名稱
  * @param {Anything} data 要額外傳遞的數據,事件處理函數參數如下
  * event = {
   // 事件類型
   type: type,
   // 綁定的源,始終為當前實例對象
   origin: this,
   // 事件處理函數中的執(zhí)行上下文 為 this 或用戶指定的上下文對象
   scope :this/scope
   // 其他數據 為fire時傳遞的數據
  }
  * @returns 事件對象
  */
 fire: function (type, data) {
  type = type.toLowerCase();
  var eventArr = this._events[type];
  var fn, scope,
   event = Object.assign({
    // 事件類型
    type: type,
    // 綁定的源
    origin: this,
    // scope 為 this 或用戶指定的上下文,
    // 是否取消
    cancel: false
   }, data);

  if (!eventArr) return event;

  for (var i = 0, l = eventArr.length; i < l; ++i) {
   fn = eventArr[i][0];
   scope = eventArr[i][1];
   if (scope) {
    event.scope = scope;
    fn.call(scope, event);
   } else {
    event.scope = this;
    fn(event);
   }
  }
  return event;
 },
 /**
  * 取消綁定一個事件
  * 
  * @param {String} type 取消綁定的事件名稱
  * @param {Function} fn 要取消綁定的事件處理函數,不指定則移除當前事件類型下的全部處理函數
  * @returns 當前實例對象
  */
 off: function (type, fn) {
  type = type.toLowerCase();
  var eventArr = this._events[type];
  if (!eventArr || !eventArr.length) return this;
  if (!fn) {
   this._events[type] = eventArr = [];
  } else {
   for (var i = 0; i < eventArr.length; ++i) {
    if (fn === eventArr[i][0]) {
     eventArr.splice(i, 1);
     // 1、找到后不能立即 break 可能存在一個事件一個函數綁定多次的情況
     // 刪除后數組改變,下一個仍然需要遍歷處理!
     --i;
    }
   }
  }
  return this;
 },
 /**
  * 綁定一個只執(zhí)行一次的事件
  * 
  * @param {String} type 事件類型
  * @param {Function} fn 事件處理函數
  * @param {Object} scope 要為事件處理函數綁定的執(zhí)行上下文
  * @returns 當前實例對象
  */
 one: function (type, fn, scope) {
  var that = this;

  function nfn() {
   // 執(zhí)行時 先取消綁定
   that.off(type, nfn);
   // 再執(zhí)行函數
   fn.apply(scope || that, arguments);
  }
  this.on(type, nfn, scope);
  return this;
 }
};

在自己的控件中使用

上面已經實現了一套事件機制,我們如何在自己的事件中使用呢。

比如我寫了一個日歷控件,需要使用事件機制。

function Calendar() {
 // 加入事件機制的存儲的對象
 this._event = {};
 // 日歷的其他實現
}
Calendar.prototype = {
 constructor:Calendar,
 on:function () {},
 off:function () {},
 fire:function () {},
 one:function () {},
 // 日歷的其他實現 。。。
}

以上偽代碼作為示意,僅需在讓控件繼承到on、off 、fire 、one等方法即可。但是必須保證事件的存儲對象_events 必須是直接加載實例上的,這點需要在繼承時注意,JavaScript中實現繼承的方案太多了。

上面為日歷控件Calendar中加入了事件機制,之后就可以在Calendar中使用了。

如在日歷開發(fā)時,我們在日歷的單元格渲染時觸發(fā)cellRender事件。

// 每天渲染時發(fā)生 還未插入頁面
var renderEvent = this.fire('cellRender', {
 // 當天的完整日期
 date: date.format('YYYY-MM-DD'),
 // 當天的iso星期
 isoWeekday: day,
 // 日歷dom
 el: this.el,
 // 當前單元格
 tdEl: td,
 // 日期文本
 dateText: text.innerText,
 // 日期class
 dateCls: text.className,
 // 需要注入的額外的html
 extraHtml: '',
 isHeader: false
});

在事件中,我們將當前渲染的日期、文本class等信息都提供給用戶,這樣用戶就可以綁定這個事件,在這個事件中進行自己的個性阿化處理了。

如在渲染時,如果是周末則插入一個"假"的標識,并讓日期顯示為紅色。

var calendar = new Calendar();
calendar.on('cellRender', function (e) {
 if(e.isoWeekday > 5 ) {
  e.extraHtml = '<span>假</span>';
  e.dateCls += ' red';
 } 
});

在控件中使用事件機制,即可簡化開發(fā),使得流程易于控制,還可為實際使用時提供非常豐富的個性化操作,快快用起來吧。

總結

以上就是這篇文章的全部內容了,希望本文的內容對大家的學習或者工作具有一定的參考學習價值,如果有疑問大家可以留言交流,謝謝大家對腳本之家的支持。

相關文章

  • 用javascript實現鼠標框選

    用javascript實現鼠標框選

    用javascript實現鼠標框選...
    2007-05-05
  • JavaScript中for of和for in的區(qū)別詳解

    JavaScript中for of和for in的區(qū)別詳解

    對于初學者,我們或許只知道無論是for of還是for in他們都有一個功能那就是遍歷,至于具體的細節(jié)或許我們不是很清楚,那么接下來我們就來詳細的區(qū)分一下for of和for in他們之間的不同點和相同點,需要的朋友可以參考下
    2023-06-06
  • js利用遞歸與promise 按順序請求數據的方法

    js利用遞歸與promise 按順序請求數據的方法

    這篇文章主要介紹了js利用遞歸與promise 按順序請求數據,需要的朋友可以參考下
    2019-08-08
  • JS實現深拷貝的幾種簡單方法示例

    JS實現深拷貝的幾種簡單方法示例

    深拷貝和淺拷貝是在JavaScript中復制對象或數組時經常遇到的概念,下面這篇文章主要給大家介紹了關于JS實現深拷貝的幾種簡單方法,文中通過代碼介紹的非常詳細,需要的朋友可以參考下
    2023-10-10
  • JS中如何實現點擊a標簽返回頁面頂部的問題

    JS中如何實現點擊a標簽返回頁面頂部的問題

    這篇文章主要介紹了JS中實現點擊a標簽返回頁面頂部的問題,非常不錯,具有參考借鑒價值,需要的的朋友參考下吧
    2017-01-01
  • IE11下使用canvas.toDataURL報SecurityError錯誤的解決方法

    IE11下使用canvas.toDataURL報SecurityError錯誤的解決方法

    這篇文章主要給大家介紹了關于在IE11下使用canvas.toDataURL報SecurityError錯誤的解決方法,文中通過示例代碼介紹的非常詳細,對同樣遇到這個問題的朋友們具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧。
    2017-11-11
  • 理解Javascript_09_Function與Object

    理解Javascript_09_Function與Object

    在《理解Javascript_08_函數對象》中講解了很多函數對象的問題,同時也留下了許多疑問,今天讓我們來解答部分問題。
    2010-10-10
  • JavaScript利用鍵盤碼控制div移動

    JavaScript利用鍵盤碼控制div移動

    這篇文章主要為大家詳細介紹了JavaScript利用鍵盤碼控制div移動,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2020-03-03
  • 微信小程序實現簡單購物車功能

    微信小程序實現簡單購物車功能

    這篇文章主要為大家詳細介紹了微信小程序實現簡單購物車功能,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2020-12-12
  • js調用圖片隱藏&顯示實現代碼

    js調用圖片隱藏&顯示實現代碼

    圖片隱藏&顯示效果,會在很多地方看到,本文使用js實現下,個人感覺還不錯,有需要的朋友不妨參考下
    2013-09-09

最新評論