事件event

浏览器事件

先捕获,再冒泡。想像成东西扔进水里再浮起来的过程。

特殊情况:如果给一个 body 中的子节点同时注册冒泡和捕获事件,事件触发会按照注册的顺序执行。

官方eventListener api学习(注意几个参数):

https://zhuanlan.zhihu.com/p/24555031

https://juejin.im/post/5cc941436fb9a03236394027#heading-3

https://developer.mozilla.org/zh-CN/docs/Web/API/EventTarget/removeEventListener

stopPropagation / stopImmediatePropagation

  • e.target 指向触发事件监听的对象。
  • e.currentTarget 指向添加监听事件的对象。

事件代理

事件代理的方式相较于直接给目标注册事件来说,有以下优点:

  • 节省内存
  • 不需要给子节点注销事件

React中的事件

事件代理。

【必读】React 事件代理与 stopImmediatePropagation: https://github.com/youngwind/blog/issues/107

并非 #child 和 #parent 的事件分别代理到 document 上,而是 React 在 document 上绑定了一个 dispatchEvent 函数(事件),在执行 dispatchEvent 的过程中,其内部会依次执行 #child 和 #parent 上绑定的事件

通过 React 绑定的事件,其回调函数中的 event 对象,是经过 React 合成的 SyntheticEvent,与原生的 DOM 事件的 event 不是一回事。准确地说,在 React 中,e.nativeEvent 才是原生 DOM 事件的那个 event,虽然 React 的合成事件对象也同样实现了 stopPropagation 接口。(注意:React合成事件里有stopPropagation,但没有stopImmediatePropagation。)

Q:点击 #child ,只触发 #child 上的事件,不要触发任何其他元素的事件,包括绑在 document上的原生事件“,我应该怎么做呢?

A:”调用e.nativeEvent.stopImmediatePropagation“。React 合成事件对象的e.stopPropagation,只能阻止 React 模拟的事件冒泡,并不能阻止真实的 DOM 事件冒泡,更加不能阻止已经触发元素的多个事件的依次执行。在这种情况下,只有原生事件对象的 stopImmediatePropagation能做到。

第三方库

1. wolfy87-eventemitter

介绍:Evented JavaScript for the browser(在浏览器里使用类似node.js的事件机制)

https://github.com/Olical/EventEmitter npm package: wolfy87-eventemitter API: https://github.com/Olical/EventEmitter/blob/master/docs/guide.md

实践经验:特别注意的地方是,必须先on监听,再emit发消息才会收到消息。

关于使用第三方库vs 原生DOM event的疑问(提问很详细)

https://github.com/Olical/EventEmitter/issues/74

作者回答:第三方库no-DOM更快。

eastbaby个人补充观点:相比DOM event,这个可以跨页面。

node.js 官方event

const events = require('events');

const emitter = new events.EventEmitter();

// 绑定sayHi事件,可以绑定多个同名事件,触发时会顺序触发
emitter.on('sayHi', function(someone){
    console.log("我是", someone)
})
emitter.on('sayHi', function(someone){
    console.log("我就是", someone)
})

// 触发sayHi事件
emitter.emit('sayHi', 'pfan');

// 我是pfan
// 我就是pfan

Node.js中大部分的模块,都继承自Event模块,来异步操作处理如request、stream。

模拟实现

function Emitter(){
  this.events = {}
}

Emitter.prototype.on = function(type, listener){
  // 在事件对象中加入新的属性
  // 确保新的属性以数组的形式保存
  this.events[type] = this.events[type] || [];
  // 在数组中加入事件处理函数
  this.events[type].push(listener);
}

Emitter.prototype.off = function(type, listener){
    if(this.events && this.events[type]){
      var i = this.events[type].length;
      while (i--) {
        if (this.events[type][i] === listener) {
          list.splice(i, 1);
        }
      }
    }
}

Emitter.prototype.once = function(type, listener){
    let self = this
    this.on(type, function(){
        self.off(type)
        listener(...arguments)
    }) // 给他监听上,执行emit的时候才会执行listner
}

Emitter.prototype.emit = function(type, arg){
  if(this.events[type]) {// 如果事件对象中含有该属性
    this.events[type].forEach(function(listener){
      listener(arg)
    })
  }
}
module.exports = Emitter;

参考:https://github.com/pfan123/Articles/issues/16

MDN 自定义事件

属于DOM事件。这些事件通常称为合成事件,而不是浏览器本身触发的事件。

CustomEvent

dispatchEvent

可以挂在document上用。

<form>
  <textarea></textarea>
</form>
----
// Create a new event, allow bubbling, and provide any data you want to pass to the "details" property
const eventAwesome = new CustomEvent('awesome', {
  bubbles: true,
  detail: { text: () => textarea.value }
});

// The form element listens for the custom "awesome" event and then consoles the output of the passed text() method
form.addEventListener('awesome', e => console.log(e.detail.text()));

// As the user types, the textarea inside the form dispatches/triggers the event to fire, and uses itself as the starting point
textarea.addEventListener('input', e => e.target.dispatchEvent(eventAwesome));

参考:https://developer.mozilla.org/zh-CN/docs/Web/Guide/Events/Creating_and_triggering_events

results matching ""

    No results matching ""