重探浏览器事件(浅析事件编程化)

站长手记 作者: 2024-08-28 03:45:01
在平常开发过程中,就算不使用现在主流的框架也至少得使用个Jquery,这些工具帮我们统一不同浏览器平台之间的差异和细节,可以将注意力集中到开发上来.不过有意思的一点是,在看完高程的N年后我居然连event对象中的target和currentTarget属性的区别都忘记了.

前言

  • 你能说出event.currentTarget和event.target的区别吗?
  • 如果可以那么event.srcElement和事件监听函数中的this呢
  • 如何使用编程的方式来触发事件,而不借助浏览器默认触发方式?
  • 如何创建一个我们自己的Event对象,然后自定义我们的事件?
  • 实现上方的内容的同时该如何兼容IE浏览器?
<button id="button">click me then change word</button>
  var button = document.getElementById('button');

  button.addEventListener('click',function (event) {
    console.log(event);
  });
firefox67 chrome72 edge44.17763.1.0 ie11 ie9
altKey altKey altKey altKey altKey
bubbles bubbles bubbles AT_TARGET AT_TARGET
button button button bubbles bubbles
buttons buttons buttons BUBBLING_PHASE BUBBLING_PHASE
cancelBubble cancelBubble cancelable button button
cancelable cancelable cancelBubble buttons buttons
clientX clientX clientX cancelable cancelable
clientY clientY clientY cancelBubble cancelBubble
composed composed ctrlKey CAPTURING_PHASE CAPTURING_PHASE
ctrlKey ctrlKey currentTarget clientX clientX
currentTarget currentTarget defaultPrevented clientY clientY
defaultPrevented defaultPrevented detail constructor constructor
detail detail eventPhase ctrlKey ctrlKey
eventPhase eventPhase fromElement currentTarget currentTarget
explicitOriginalTarget fromElement height defaultPrevented defaultPrevented
isTrusted isTrusted isPrimary detail detail
layerX layerX isTrusted deviceSessionId eventPhase
layerY layerY layerX eventPhase fromElement
metaKey metaKey layerY fromElement isTrusted
movementX movementX metaKey height layerX
movementY movementY movementX hwTimestamp layerY
mozInputSource offsetX movementY isPrimary metaKey
mozPressure offsetY offsetX isTrusted offsetX
offsetX pageX offsetY layerX offsetY
offsetY pageY pageX layerY pageX
originalTarget path pageY metaKey pageY
pageX relatedTarget pointerId offsetX relatedTarget
pageY returnValue pointerType offsetY screenX
rangeOffset screenX pressure pageX screenY
rangeParent screenY relatedTarget pageY shiftKey
region shiftKey returnValue pointerId srcElement
relatedTarget sourceCapabilities screenX pointerType target
returnValue srcElement screenY pressure timeStamp
screenX target shiftKey relatedTarget toElement
screenY timeStamp srcElement rotation type
shiftKey toElement target screenX view
srcElement type tiltX screenY which
target view tiltY shiftKey x
timeStamp which timeStamp srcElement y
type x toElement target
view y twist tiltX
which type tiltY
x view timeStamp
y which toElement
width type
x view
y which
width
x
y

currentTarget,target,srcElement,this

currentTarget

this

button.addEventListener('click',function (event) {
      console.log(event.currentTarget === this); // true
});

target

  <div id="wrap">
    <button id="button">test click</button>
  </div>
    var 
      wrap = document.getElementById('wrap'),
      button = document.getElementById('button');

    // 注意我们监听的是wrap的click事件,而不是button的click事件
    wrap.addEventListener('click',function (event) {
      
      // event.target指向的是按钮,因为我们点击的是按钮
      console.log(event.target === button && event.target === event.srcElement); // true

      // 当我们点击按钮触发的事件冒泡到了wrap,所以触发了wrap的click事件,
      // 此时currentTarget指向的是wrap
      console.log(wrap===this && wrap === event.currentTarget); // true

      // 直接打印event然后控制台中查看currentTaget会返回null
      // 你可以将他赋值到一个变量在打印输出这个变量
      // see https://github.com/vuejs/vue/issues/6867#issuecomment-338195468
    })
  • this 和 currentTarget指向的都是添加了监听器的对象这里就是wrap
  • target 和 srcElement指向的是触发了事件的元素
// Make a list
var ul = document.createElement('ul');
document.body.appendChild(ul);

var li1 = document.createElement('li');
var li2 = document.createElement('li');
ul.appendChild(li1);
ul.appendChild(li2);

function hide(e){
  // e.target 引用着 <li> 元素
  // 不像 e.currentTarget 引用着其父级的 <ul> 元素.
  e.target.style.visibility = 'hidden';
}

// 添加监听事件到列表,当每个 <li> 被点击的时候都会触发。
ul.addEventListener('click', hide, false);
https://developer.mozilla.org...

srcElement

Event.srcElement 是标准的 Event.target 属性的一个别名。它只对老版本的IE浏览器有效。

完整的事件编程

EventTarget接口

  • elem.addEventListener
  • elem.removeEventListener
  • elem.dispatchEvent
    const a = new EventTarget;

    a.addEventListener('click',()=>{
      
    })
  • 继承EventTarget而不是直接使用EventTarget的实例,
  • 在事件监听函数中传递Event对象
  • 找个地方来触发这个事件

继承EventTarget

    // --- 包装EventTarget开始
    function MyEventTarget() {
      var target = document.createTextNode(null);
      this.addEventListener = target.addEventListener.bind(target);
      this.removeEventListener = target.removeEventListener.bind(target);
      this.dispatchEvent = target.dispatchEvent.bind(target);
    }
    MyEventTarget.prototype = EventTarget.prototype;
    // --- 包装EventTarget结束

    // --- 创建我们继承EventTarget的构造函数
    function myElem() {
      
    }

    myElem.prototype = new MyEventTarget;
    myElem.prototype.constructor = myElem;

    // 创建实例
    const instance = new myElem();

instance.addEventListener('click',()=>{
    // 现在我们实例可以监听事件了
});

    console.log(instance);
详细参考:https://stackoverflow.com/que...


创建我们的Event对象

document.getElementById('button').addEventListener('click',(event)=>{
      // event
      console.log(event);
    })
// 使用全局的Event
new Event('test',{ // 事件类型
      bubbles:false, // 是否冒泡 默认false
      cancelable:false,// 是否可以被取消 默认false
    });
https://developer.mozilla.org...
  • event.target
  • event.currentTarget
  • event.preventDefault()
  1. 第一套比较新的API提供了现代的接口,也就是之前例子中的方式.
    在创建一个已有的事件的时候,你只需要使用全局的构造函数就可以,
    例如:new MouseEvent('test',/*对应MouseEvent的参数选项*/),
    但是缺点就是不支持IE浏览器.
  2. 第二套API支持IE浏览器,但是使用过程比较繁琐
    使用Event.createEvent(/*事件类型*/)创建对应事件类型的Event对象,
    使用Event.initEvent()来初始化事件,并且提供对应事件类型的参数,
    如果你创建一个MouseEvent类型的事件InitEvent方法最多需要15个参数.
    这种情况下使用new MouseEvent()传入对象配置的形式就简单多了.
一篇值得参考的文章,使用createEvent api

触发我们的事件

    function MyEventTarget() {
      var target = document.createTextNode(null);
      this.addEventListener = target.addEventListener.bind(target);
      this.removeEventListener = target.removeEventListener.bind(target);
      this.dispatchEvent = target.dispatchEvent.bind(target);
    }
    MyEventTarget.prototype = EventTarget.prototype;
    function myElem() {

    }

    myElem.prototype = new MyEventTarget;
    myElem.prototype.constructor = myElem;

    const instance = new myElem();

    instance.addEventListener('test', (event) => {
      console.log(event); // 监听事件并且打印实例
    });

    const myEvent = new Event('test'); // 创建Event实例

    instance.dispatchEvent(myEvent); // 触发事件
详细参考https://developer.mozilla.org...

编程式的事件触发

<div id="wrap">
    <button id="button">test click</button>
</div>
    const
      button = document.getElementById('button'),
      wrap = document.getElementById('wrap');

    wrap.addEventListener('click', (event) => {
      console.log(event); // 打印event对象
    });

    const myEvent1 = new Event('click', {
      bubbles: false, // 不可以冒泡
    });

    const myEvent2 = new Event('click', {
      bubbles: true, // 可以冒泡
    });

    button.dispatchEvent(myEvent1); // 这次没有打印出内容
    button.dispatchEvent(myEvent2); // 这次打印出了内容
  • dispatchEvent执行的时候只要是Event的实例且类型相同那么监听器就会被触发.
  • bubbles参数可以控制该事件是否允许冒泡
原创声明
本站部分文章基于互联网的整理,我们会把真正“有用/优质”的文章整理提供给各位开发者。本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
本文链接:http://www.jiecseo.com/news/show_69912.html