JS新Web API:EventTarget.when(上)

1.先看个demo,袁老师讲了个例子:以同步方式实现事件监听,咱们使用新的API来实现下,要求是:在循环中等待按钮点击

async function watiClick() {
  const el = document.getElementById('btn')
  const observer = el.when('click')
    let i = 0
    async function clicked() {
      return new Promise(resolve => {
        i++
        observer.subscribe(resolve)
      })
    }
    while (true) {
      await clicked()
      console.log('点击次数', i);
      console.log('clicked')
    }
  }
  watiClick()
image.png

2.用法:const observer = eventTarget.when(eventType);

  • eventTarget: 任何继承自 EventTarget 的对象,如 HTMLElement、Window、XMLHttpRequest、Web Socket 等。
  • eventType: 字符串,表示要监听的事件类型(如 'click'、'load'、'input')
  • observer: Observer实例对象,包含方法如图:


    observer实例

3.实例方法

  • subscribe: 事件触发后通过该方法订阅了才能获得结果,observer.subscribe(参数1,参数2),参数2需要是一个SubscribeOptions对象,具体内容目前不知,参数1可以是一个回调方法也可以是个含next和error的对象
observer.subscribe(event=> {
    console.log(event,'事件触发了') // 事件对象
})
observer .subscribe({
   next(event) {
      console.log(event, '事件触发了') // 事件对象
    },
    error(err) {
        console.log(err);
    }
})
image.png

既然订阅了事件那么就应该有取消订阅的方法,如const unSubscribe = observer.subscribe(...),可惜没有,unSubscribe为undefined,subscribe没有返回值,那就不能取消订阅了吗?当然不是,别忘了还有takeUntil方法,后面讲。

  • filter: 过滤事件,按钮点击后会触发filter方法,同时打印触发次数time,time从0开始递增,当满足条件(按住Shift键的点击),subscribe方法的回调会触发
button.when('click')
  .filter((event, time) => {
    console.log(time);
    return event.shiftKey
  }) // 只处理按住Shift键的点击
  .subscribe(event => {
    console.log('Shift + Click!',);
  });
image.png
  • map: 转换事件
button.when('click')
  .map((event, time) => {
      console.log(time + '点击的次数') 
        return { dx: event.clientX, dy: event.clientY }
      }) 
  .subscribe(result => {
       console.log(result);// {dx: 30, dy: 22}
  });
image.png
  • every: 事件触发满足条件e.clientY < 100则不会打印res,不满足条件后才会打印res,同时该方法不会再调用了,该方法不会返回observer,因此不能再链式调用subscribe
const res = await document.when('click')
  .every(function (e, time) {
    console.log('e.clientY:' + e.clientY)
    return e.clientY < 100
  },)
 console.log('事件已终止,res的结果是:', res);
image.png
  • some: 和every类似,事件触发满足条件e.clientX > 500时会一直调用some方法,除非满足条件则会打印res结果为true,同时该方法不会再调用了,该方法不会返回observer,不能再链式调用subscribe
const res = await document.when('click')
  .some(function (e, time) {
    console.log('e.clientX:' + e.clientX)
    return e.clientX > 500
  },)
 console.log('事件已终止,res的结果是:', res);
image.png
  • take: 使用 take(n) 限制事件次数,下面点击事件只会触发3次,结合map方法,能看到触发次数
document.when('click')
  .take(3)
  .map((e, t) => {
    console.log('点击次数: ', t);
    return { dx: e.clientX, dy: e.clientY }
  })
  .subscribe(e => {
    console.log(e);
  })
image.png
  • drop: 使用 drop(n)跳过前 n 个事件,可以单独使用也可以结合take方法使用,其调用位置会影响其他方法的调用
document.when('click')
  .take(3)
  .drop(1)
  .map((e, t) => {
    console.log('点击次数: ', t);
      return { dx: e.clientX, dy: e.clientY }
  })
  .subscribe(e => {
    console.log(e);
  })

上面drop方法在take方法和map方法中间调用,第一点击事件触发,不会触发mapsubscribe,后面两次会触发

9f9a496f-c723-4467-a1b6-9bbefa7b85e8.png

document.when('click')
  .drop(1)
  .take(3)
  .map((e, t) => {
    console.log('点击次数: ', t);
      return { dx: e.clientX, dy: e.clientY }
  })
  .subscribe(e => {
    console.log(e);
  })

上面droptake之前调用,第一点击事件触发,但不影响后两个方法的触发,后面还是会触发3次事件,等于总共点击了4次,第一次被丢弃了

e5706027-2f20-460c-9ae2-2d35274a9215.png

document.when('click')
  .take(3)
  .map((e, t) => {
    console.log('点击次数: ', t);
      return { dx: e.clientX, dy: e.clientY }
  })
  .drop(1)
  .subscribe(e => {
    console.log(e);
 })

上面drop放在了map后面,map会触发3次回调,subscribe只会触发2次

image.png

  • takeUntil: 使用 takeUntil() 控制订阅,下面例子点击3次后不再订阅点击事件
function handleClick() {
  const stopSignal = new EventTarget();
  let i = 0
  document.when('click')
    .takeUntil(stopSignal.when('stop'))
    .map((e, t) => {
      console.log('点击次数: ', t);
      return { dx: e.clientX, dy: e.clientY }
    })
    .subscribe(e => {
       i++
       console.log('i', i);
      if (i === 3) {
        console.log('停止订阅');
        stopSignal.dispatchEvent(new Event('stop'));
      }
      console.log(e);
    })
  }
handleClick()
image.png
  • first: first调用后只会触发一次事件并返回结果,即使调用了take(3)希望触发三次,但最后调用了first()最终只会触发一次,该方法不会返回observer,因此不能再链式调用subscribe
 const res = await document.when('click').take(3)
  .map(e => ({ dx: e.clientX, dy: e.clientY }))
  .first()
  console.log('点击后只会触发一次:', res);
image.png
  • last: last调用只会在最后一次触发事件返回结果,结合take方法使用能看到效果,该方法不会返回observer,因此不能再链式调用subscribe
const res = await document.when('click').take(3)
   .map((e, t) => {
      console.log('点击次数:', t);
      return ({ dx: e.clientX, dy: e.clientY })
    })
  .last()
 console.log('点击3次后打印结果为:', res);
image.png
  • find: 此方法在找到满足的条件后才会返回结果,返回结果后事件不再触发,该方法不会返回observer,因此不能再链式调用subscribe
const observer = document.when('click');
const e = await observer.find((event, t,) => {
  console.log('点击次数:', t);
    return event.target.id === 'btn'
  })
console.log(e.target);
image.png
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容