成人午夜视频全免费观看高清-秋霞福利视频一区二区三区-国产精品久久久久电影小说-亚洲不卡区三一区三区一区

Javascript事件機制兼容性解決方法是什么

本篇內(nèi)容主要講解“Javascript事件機制兼容性解決方法是什么”,感興趣的朋友不妨來看看。本文介紹的方法操作簡單快捷,實用性強。下面就讓小編來帶大家學(xué)習(xí)“Javascript事件機制兼容性解決方法是什么”吧!

創(chuàng)新互聯(lián)專注于淇縣網(wǎng)站建設(shè)服務(wù)及定制,我們擁有豐富的企業(yè)做網(wǎng)站經(jīng)驗。 熱誠為您提供淇縣營銷型網(wǎng)站建設(shè),淇縣網(wǎng)站制作、淇縣網(wǎng)頁設(shè)計、淇縣網(wǎng)站官網(wǎng)定制、成都微信小程序服務(wù),打造淇縣網(wǎng)絡(luò)公司原創(chuàng)品牌,更為您提供淇縣網(wǎng)站排名全網(wǎng)營銷落地服務(wù)。

本文的解決方案可以用于Javascript native對象和宿主對象(dom元素),通過以下的方式來綁定和觸發(fā)事件:

Javascript事件機制兼容性解決方法是什么

或者

var input = document.getElementsByTagName('input')[0];  var form = document.getElementsByTagName('form')[0];  Evt.on(input, 'click', function(evt){      console.log('input click1');      console.log(evt.target === input);      console.log(evt.modified);      //evt.stopPropagation();      console.log(evt.modified);  });  var handle2 = Evt.on(input, 'click', function(evt){      console.log('input click2');      console.log(evt.target === input);      console.log(evt.modified);  });  Evt.on(form, 'click', function(evt){      console.log('form click');      console.log(evt.currentTarget === input);      console.log(evt.target === input);      console.log(evt.currentTarget === form);      console.log(evt.modified);  });  Evt.emit(input, 'click');  Evt.emit(input, 'click', {bubbles: true});  handle2.remove();  Evt.emit(input, 'click');

After函數(shù)

為native對象添加事件的過程主要在after函數(shù)中完成,這個函數(shù)主要做了以下幾件事:

  1. 如果obj中已有響應(yīng)函數(shù),將其替換成dispatcher函數(shù)

  2. 使用鏈式結(jié)構(gòu),保證多次綁定事件函數(shù)的順序執(zhí)行

  3. 返回一個handle對象,調(diào)用remove方法可以去除本次事件綁定

下圖為after函數(shù)調(diào)用前后onlog函數(shù)的引用

Javascript事件機制兼容性解決方法是什么

(調(diào)用前)

Javascript事件機制兼容性解決方法是什么

(調(diào)用后)

詳細解釋請看注釋,希望讀者能夠跟著運行一遍

var after = function(target, method, cb, originalArgs){      var existing = target[method];      var dispatcher = existing;      if (!existing || existing.target !== target) {          //如果target中沒有method方法,則為他添加一個方法method方法          //如果target已經(jīng)擁有method方法,但target[method]中target不符合要求則將method方法他替換          dispatcher = target[method] = function(){              //由于js是此法作用域:通過閱讀包括變量定義在內(nèi)的數(shù)行源碼就能知道變量的作用域。              //局部變量在聲明它的函數(shù)體內(nèi)以及其所嵌套的函數(shù)內(nèi)始終是有定義的              //所以在這個函數(shù)中可以訪問到dispatcher變量              var results = null;              var args = arguments;              if (dispatcher.around) {//如果原先擁有method方法,先調(diào)用原始method方法                  //此時this關(guān)鍵字指向target所以不用target                  results = dispatcher.around.advice.apply(this, args);              }                            if (dispatcher.after) {//如果存在after鏈則依次訪問其中的advice方法                  var _after = dispatcher.after;                  while(_after && _after.advice) {                      //如果需要原始參數(shù)則傳入arguments否則使用上次執(zhí)行結(jié)果作為參數(shù)                      args = _after.originalArgs ? arguments : results;                      results = _after.advice.apply(this, args);                      _after = _after.next;                  }              }          }                    if (existing) {          //函數(shù)也是對象,也可以擁有屬性跟方法          //這里將原有的method方法放到dispatcher中              dispatcher.around = {                  advice: function(){                      return existing.apply(target, arguments);                  }              }          }          dispatcher.target = target;      }                  var signal = {          originalArgs: originalArgs,//對于每個cb的參數(shù)是否使用最初的arguments          advice: cb,          remove: function() {              if (!signal.advice) {                  return;              }              //remove的本質(zhì)是將cb從函數(shù)鏈中移除,刪除所有指向他的鏈接              var previous = signal.previous;              var next = signal.next;              if (!previous && !next) {                  dispatcher.after = signal.advice = null;                  dispatcher.target = null;                  delete dispatcher.after;              } else if (!next){                  signal.advice = null;                  previous.next = null;                  signal.previous = null;              } else if (!previous){                  signal.advice = null;                  dispatcher.after = next;                  next.previous = null;                  signal.next = null;              } else {                  signal.advice = null;                  previous.next = next;                  next.previous = previous;                  signal.previous = null;                  signal.next = null;              }          }      }                  var previous = dispatcher.after;      if (previous) {//將signal加入到鏈式結(jié)構(gòu)中,處理指針關(guān)系          while(previous && previous.next && (previous = previous.next)){};          previous.next = signal;          signal.previous = previous;      } else {//如果是***次使用調(diào)用after方法,則dispatcher的after屬性指向signal          dispatcher.after = signal;      }            cb = null;//防止內(nèi)存泄露      return signal;  }

解決兼容性

IE瀏覽器從IE9開始已經(jīng)支持DOM2事件處理程序,但是對于老版本的ie瀏覽器,任然使用attachEvent方式來為dom元素添加事件。值得慶幸的是微軟已宣布2016年將不再對ie8進行維護,對于廣大前端開發(fā)者無疑是一個福音。然而在曙光來臨之前,仍然需要對那些不支持DOM2級事件處理程序的瀏覽器進行兼容性處理,通常需要處理以下幾點:

  1. 多次綁定一個事件,事件處理函數(shù)的調(diào)用順序問題

  2. 事件處理函數(shù)中的this關(guān)鍵字指向問題

  3. 標準化event事件對象,支持常用的事件屬性

由于使用attachEvent方法添加事件處理函數(shù)無法保證事件處理函數(shù)的調(diào)用順序,所以我們棄用attachEvent,轉(zhuǎn)而用上文中的after生成的正序鏈式結(jié)構(gòu)來解決這個問題。

//1、統(tǒng)一事件觸發(fā)順序      function fixAttach(target, type, listener) {      debugger;          var listener = fixListener(listener);          var method = 'on' + type;          return after(target, method, listener, true);      };

對于事件處理函數(shù)中的this關(guān)鍵字指向,通過閉包即可解決(出處),如:

Javascript事件機制兼容性解決方法是什么

本文也是通過這種方式解決此問題

//1、統(tǒng)一事件觸發(fā)順序      function fixAttach(target, type, listener) {      debugger;          var listener = fixListener(listener);          var method = 'on' + type;          return after(target, method, listener, true);      };            function fixListener(listener) {          return function(evt){              //每次調(diào)用listenser之前都會調(diào)用fixEvent              debugger;              var e = _fixEvent(evt, this);//this作為currentTarget              if (e && e.cancelBubble && (e.currentTarget !== e.target)){                  return;              }              var results =  listener.call(this, e);               if (e && e.modified) {                  // 在整個函數(shù)鏈執(zhí)行完成后將lastEvent回歸到原始狀態(tài),                  //利用異步隊列,在主程序執(zhí)行完后再執(zhí)行事件隊列中的程序代碼                  //常規(guī)的做法是在emit中判斷l(xiāng)astEvent并設(shè)為null                  //這充分體現(xiàn)了js異步編程的優(yōu)勢,把變量賦值跟清除代碼放在一起,避免邏輯分散,缺點是不符合程序員正常思維方式                  if(!lastEvent){                      setTimeout(function(){                          lastEvent = null;                      });                  }                  lastEvent = e;              }              return results;          }      }

對于事件對象的標準化,我們需要將ie提供給我們的現(xiàn)有屬性轉(zhuǎn)化為標準的事件屬性。

function _fixEvent(evt, sender){          if (!evt) {              evt = window.event;          }          if (!evt) { // emit沒有傳遞事件參數(shù),或者通過input.onclick方式調(diào)用              return evt;          }          if(lastEvent && lastEvent.type && evt.type == lastEvent.type){          //使用一個全局對象來保證在冒泡過程中訪問的是同一個event對象          //chrome中整個事件處理過程event是***的              evt = lastEvent;          }          var fixEvent = evt;          // bubbles 和cancelable根據(jù)每次emit時手動傳入?yún)?shù)設(shè)置          fixEvent.bubbles = typeof evt.bubbles !== 'undefined' ? evt.bubbles : false;          fixEvent.cancelable = typeof evt.cancelable !== 'undefined' ? evt.cancelable : true;          fixEvent.currentTarget = sender;          if (!fixEvent.target){ // 多次綁定統(tǒng)一事件,只fix一次              fixEvent.target = fixEvent.srcElement || sender;                            fixEvent.eventPhase = fixEvent.target === sender ? 2 : 3;              if (!fixEvent.preventDefault) {                  fixEvent.preventDefault = _preventDefault;                  fixEvent.stopPropagation = _stopPropagation;                  fixEvent.stopImmediatePropagation = _stopImmediatePropagation;              }              //參考:http://www.nowamagic.net/javascript/js_EventMechanismInDetail.php              if( fixEvent.pageX == null && fixEvent.clientX != null ) {                  var doc = document.documentElement, body = document.body;                  fixEvent.pageX = fixEvent.clientX + (doc && doc.scrollLeft || body && body.scrollLeft || 0) - (doc && doc.clientLeft || body && body.clientLeft || 0);                  fixEvent.pageY = fixEvent.clientY + (doc && doc.scrollTop  || body && body.scrollTop  || 0) - (doc && doc.clientTop  || body && body.clientTop  || 0);              }              if (!fixEvent.relatedTarget && fixEvent.fromEvent) {                  fixEvent.relatedTarget = fixEvent.fromEvent === fixEvent.target ? fixEvent.toElement : fixEvent.fromElement;              }              // 參考: http://www.cnblogs.com/hsapphire/archive/2009/12/18/1627047.html              if (!fixEvent.which && fixEvent.keyCode) {                  fixEvent.which = fixEvent.keyCode;              }          }                    return fixEvent;      }            function _preventDefault(){          this.defaultPrevented = true;          this.returnValue = false;           this.modified = true;      }            function _stopPropagation(){          this.cancelBubble = true;           this.modified = true;      }            function _stopImmediatePropagation(){          this.isStopImmediatePropagation = true;          this.modified = true;      }

在_preventDefault、_stopPropagation、_stopImmediatePropagation三個函數(shù)中我們,如果被調(diào)用則listener執(zhí)行完后使用一個變量保存event對象(見fixListener),以便后序事件處理程序根據(jù)event對象屬性進行下一步處理。stopImmediatePropagation函數(shù),對于這個函數(shù)的模擬,我們同樣通過閉包來解決。

Javascript事件機制兼容性解決方法是什么

Javascript事件機制兼容性解決方法是什么

注意這里不能直接寫成這種形式,上文中fixListener也是同樣道理。

Javascript事件機制兼容性解決方法是什么

需要注意一點,我們將event標準化目的還有一點,可以在emit方法中設(shè)置參數(shù)來控制事件過程,比如:

Evt.emit(input, 'click');//不冒泡  Evt.emit(input, 'click', {bubbles: true});//冒泡

根據(jù)我的測試使用fireEvent方式觸發(fā)事件,無法設(shè)置{bubbles:false}來阻止冒泡,所以這里我們用Javascript來模擬冒泡過程。同時在這個過程中也要保證event對象的***性。

// 模擬冒泡事件      var sythenticBubble = function(target, type, evt){          var method = 'on' + type;          var args = Array.prototype.slice.call(arguments, 2);          // 保證使用emit觸發(fā)dom事件時,event的有效性          if ('parentNode' in target) {              var newEvent = args[0] = {};              for (var p in evt) {                  newEvent[p] = evt[p];              }                            newEvent.preventDefault = _preventDefault;              newEvent.stopPropagation = _stopPropagation;              newEvent.stopImmediatePropagation = _stopImmediatePropagation;              newEvent.target = target;              newEvent.type = type;          }                    do{              if (target && target[method]) {                  target[method].apply(target, args);              }          }while(target && (target = target.parentNode) && target[method] && newEvent && newEvent.bubbles);      }            var emit = function(target, type, evt){          if (target.dispatchEvent && document.createEvent){              var newEvent = document.createEvent('HTMLEvents');              newEvent.initEvent(type, evt && !!evt.bubbles, evt && !!evt.cancelable);              if (evt) {                  for (var p in evt){                      if (!(p in newEvent)){                          newEvent[p] = evt[p];                      }                  }              }                            target.dispatchEvent(newEvent);          } /*else if (target.fireEvent) {              target.fireEvent('on' + type);// 使用fireEvent在evt參數(shù)中設(shè)置bubbles:false無效,所以棄用          } */else {              return sythenticBubble.apply(on, arguments);          }      }

附上完整代碼:

<!DOCTYPE html> <html> <head> <meta http-equiv="Content-Type" content="text/html;charset=utf-8"/> <meta http-equiv="window-target" content="_top"> <title>Writing to Same Doc</title> <script language="JavaScript"> var after = function(target, method, cb, originalArgs){      var existing = target[method];      var dispatcher = existing;      if (!existing || existing.target !== target) {          //如果target中沒有method方法,則為他添加一個方法method方法          //如果target已經(jīng)擁有method方法,但target[method]中target不符合要求則將method方法他替換          dispatcher = target[method] = function(){              //由于js是此法作用域:通過閱讀包括變量定義在內(nèi)的數(shù)行源碼就能知道變量的作用域。              //局部變量在聲明它的函數(shù)體內(nèi)以及其所嵌套的函數(shù)內(nèi)始終是有定義的              //所以在這個函數(shù)中可以訪問到dispatcher變量              var results = null;              var args = arguments;              if (dispatcher.around) {//如果原先擁有method方法,先調(diào)用原始method方法                  //此時this關(guān)鍵字指向target所以不用target                  results = dispatcher.around.advice.apply(this, args);              }                            if (dispatcher.after) {//如果存在after鏈則依次訪問其中的advice方法                  var _after = dispatcher.after;                  while(_after && _after.advice) {                      //如果需要原始參數(shù)則傳入arguments否則使用上次執(zhí)行結(jié)果作為參數(shù)                      args = _after.originalArgs ? arguments : results;                      results = _after.advice.apply(this, args);                      _after_after = _after.next;                  }              }          }                    if (existing) {          //函數(shù)也是對象,也可以擁有屬性跟方法          //這里將原有的method方法放到dispatcher中              dispatcher.around = {                  advice: function(){                      return existing.apply(target, arguments);                  }              }          }          dispatcher.target = target;      }                  var signal = {          originalArgs: originalArgs,//對于每個cb的參數(shù)是否使用最初的arguments          advice: cb,          remove: function() {              if (!signal.advice) {                  return;              }              //remove的本質(zhì)是將cb從函數(shù)鏈中移除,刪除所有指向他的鏈接              var previous = signal.previous;              var next = signal.next;              if (!previous && !next) {                  dispatcher.after = signal.advice = null;                  dispatcher.target = null;                  delete dispatcher.after;              } else if (!next){                  signal.advice = null;                  previous.next = null;                  signal.previous = null;              } else if (!previous){                  signal.advice = null;                  dispatcher.after = next;                  next.previous = null;                  signal.next = null;              } else {                  signal.advice = null;                  previous.next = next;                  next.previous = previous;                  signal.previous = null;                  signal.next = null;              }          }      }                  var previous = dispatcher.after;      if (previous) {//將signal加入到鏈式結(jié)構(gòu)中,處理指針關(guān)系          while(previous && previous.next && (previousprevious = previous.next)){};          previous.next = signal;          signal.previous = previous;      } else {//如果是***次使用調(diào)用after方法,則dispatcher的after屬性指向signal          dispatcher.after = signal;      }            cb = null;//防止內(nèi)存泄露      return signal;  }   //1、統(tǒng)一事件觸發(fā)順序  //2、標準化事件對象  //3、模擬冒泡 emit時保持冒泡行為,注意input.onclick這種方式是不冒泡的  //4、保持冒泡過程中event的***性   window.Evt = (function(){      var on = function(target, type, listener){      debugger;          if (!listener){              return;          }          // 處理stopImmediatePropagation,通過包裝listener來支持stopImmediatePropagation          if (!(window.Event && window.Event.prototype && window.Event.prototype.stopImmediatePropagation)) {              listener = _addStopImmediate(listener);          }                if (target.addEventListener) {              target.addEventListener(type, listener, false);                            return {                  remove: function(){                      target.removeEventListener(type, listener);                  }              }          } else {              return fixAttach(target, type, listener);          }      };      var lastEvent; // 使用全局變量來保證一個元素的多個listenser中事件對象的一致性,冒泡過程中事件對象的一致性;在chrome這些過程中使用的是同一個event      //1、統(tǒng)一事件觸發(fā)順序      function fixAttach(target, type, listener) {      debugger;          var listener = fixListener(listener);          var method = 'on' + type;          return after(target, method, listener, true);      };            function fixListener(listener) {          return function(evt){              //每次調(diào)用listenser之前都會調(diào)用fixEvent              debugger;              var e = _fixEvent(evt, this);//this作為currentTarget              if (e && e.cancelBubble && (e.currentTarget !== e.target)){                  return;              }              var results =  listener.call(this, e);               if (e && e.modified) {                  // 在整個函數(shù)鏈執(zhí)行完成后將lastEvent回歸到原始狀態(tài),                  //利用異步隊列,在主程序執(zhí)行完后再執(zhí)行事件隊列中的程序代碼                  //常規(guī)的做法是在emit中判斷l(xiāng)astEvent并設(shè)為null                  //這充分體現(xiàn)了js異步編程的優(yōu)勢,把變量賦值跟清除代碼放在一起,避免邏輯分散,缺點是不符合程序員正常思維方式                  if(!lastEvent){                      setTimeout(function(){                          lastEvent = null;                      });                  }                  lastEvent = e;              }              return results;          }      }            function _fixEvent(evt, sender){          if (!evt) {              evt = window.event;          }          if (!evt) { // emit沒有傳遞事件參數(shù),或者通過input.onclick方式調(diào)用              return evt;          }          if(lastEvent && lastEvent.type && evt.type == lastEvent.type){          //使用一個全局對象來保證在冒泡過程中訪問的是同一個event對象          //chrome中整個事件處理過程event是***的              evt = lastEvent;          }          var fixEvent = evt;          // bubbles 和cancelable根據(jù)每次emit時手動傳入?yún)?shù)設(shè)置          fixEvent.bubbles = typeof evt.bubbles !== 'undefined' ? evt.bubbles : false;          fixEvent.cancelable = typeof evt.cancelable !== 'undefined' ? evt.cancelable : true;          fixEvent.currentTarget = sender;          if (!fixEvent.target){ // 多次綁定統(tǒng)一事件,只fix一次              fixEventfixEvent.target = fixEvent.srcElement || sender;                            fixEventfixEvent.eventPhase = fixEvent.target === sender ? 2 : 3;              if (!fixEvent.preventDefault) {                  fixEvent.preventDefault = _preventDefault;                  fixEvent.stopPropagation = _stopPropagation;                  fixEvent.stopImmediatePropagation = _stopImmediatePropagation;              }              //參考:http://www.nowamagic.net/javascript/js_EventMechanismInDetail.php              if( fixEvent.pageX == null && fixEvent.clientX != null ) {                  var doc = document.documentElement, body = document.body;                  fixEventfixEvent.pageX = fixEvent.clientX + (doc && doc.scrollLeft || body && body.scrollLeft || 0) - (doc && doc.clientLeft || body && body.clientLeft || 0);                  fixEventfixEvent.pageY = fixEvent.clientY + (doc && doc.scrollTop  || body && body.scrollTop  || 0) - (doc && doc.clientTop  || body && body.clientTop  || 0);              }              if (!fixEvent.relatedTarget && fixEvent.fromEvent) {                  fixEventfixEvent.relatedTarget = fixEvent.fromEvent === fixEvent.target ? fixEvent.toElement : fixEvent.fromElement;              }              // 參考: http://www.cnblogs.com/hsapphire/archive/2009/12/18/1627047.html              if (!fixEvent.which && fixEvent.keyCode) {                  fixEventfixEvent.which = fixEvent.keyCode;              }          }                    return fixEvent;      }            function _preventDefault(){          this.defaultPrevented = true;          this.returnValue = false;           this.modified = true;      }            function _stopPropagation(){          this.cancelBubble = true;           this.modified = true;      }            function _stopImmediatePropagation(){          this.isStopImmediatePropagation = true;          this.modified = true;      }            function _addStopImmediate(listener) {          return function(evt) { // 除了包裝listener外,還要保證所有的事件函數(shù)共用一個evt對象              if (!evt.isStopImmediatePropagation) {                  //evt.stopImmediatePropagation = _stopImmediateProgation;                  return listener.apply(this, arguments);              }          }      }            // 模擬冒泡事件      var sythenticBubble = function(target, type, evt){          var method = 'on' + type;          var args = Array.prototype.slice.call(arguments, 2);          // 保證使用emit觸發(fā)dom事件時,event的有效性          if ('parentNode' in target) {              var newEvent = args[0] = {};              for (var p in evt) {                  newEvent[p] = evt[p];              }                            newEvent.preventDefault = _preventDefault;              newEvent.stopPropagation = _stopPropagation;              newEvent.stopImmediatePropagation = _stopImmediatePropagation;              newEvent.target = target;              newEvent.type = type;          }                    do{              if (target && target[method]) {                  target[method].apply(target, args);              }          }while(target && (targettarget = target.parentNode) && target[method] && newEvent && newEvent.bubbles);      }            var emit = function(target, type, evt){          if (target.dispatchEvent && document.createEvent){              var newEvent = document.createEvent('HTMLEvents');              newEvent.initEvent(type, evt && !!evt.bubbles, evt && !!evt.cancelable);              if (evt) {                  for (var p in evt){                      if (!(p in newEvent)){                          newEvent[p] = evt[p];                      }                  }              }                            target.dispatchEvent(newEvent);          } /*else if (target.fireEvent) {              target.fireEvent('on' + type);// 使用fireEvent在evt參數(shù)中設(shè)置bubbles:false無效,所以棄用          } */else {              return sythenticBubble.apply(on, arguments);          }      }            return {          on: on,          emit: emit      };  })()  </script> <style type="text/css"></style> </head> <body>   <form>     <input type="button" value="Replace Content" >   </form> </body> </html>

到此,相信大家對“Javascript事件機制兼容性解決方法是什么”有了更深的了解,不妨來實際操作一番吧!這里是創(chuàng)新互聯(lián)網(wǎng)站,更多相關(guān)內(nèi)容可以進入相關(guān)頻道進行查詢,關(guān)注我們,繼續(xù)學(xué)習(xí)!

網(wǎng)頁標題:Javascript事件機制兼容性解決方法是什么
鏈接URL:http://jinyejixie.com/article18/igogdp.html

成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供微信公眾號、網(wǎng)站建設(shè)、網(wǎng)站內(nèi)鏈虛擬主機、企業(yè)建站、云服務(wù)器

廣告

聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請盡快告知,我們將會在第一時間刪除。文章觀點不代表本網(wǎng)站立場,如需處理請聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時需注明來源: 創(chuàng)新互聯(lián)

外貿(mào)網(wǎng)站建設(shè)
浦东新区| 新昌县| 衡水市| 巩义市| 漳平市| 九龙坡区| 岳西县| 林周县| 突泉县| 门源| 新干县| 麦盖提县| 奈曼旗| 淮安市| 康定县| 普定县| 民和| 南昌县| 诸城市| 莆田市| 南昌县| 且末县| 义马市| 吉木乃县| 吉木乃县| 汕尾市| 罗源县| 台湾省| 怀化市| 赤城县| 湖南省| 关岭| 武城县| 子长县| 茌平县| 犍为县| 馆陶县| 百色市| 甘肃省| 静乐县| 东港市|