JavaScript 异步之自定义事件写法

8,077 阅读2分钟

「这是我参与2022首次更文挑战的第28天,活动详情查看:2022首次更文挑战」。

写在前面

  • 前面一篇文章已经实现了我们想要的 dom 元素的运动
  • 但是里面涉及到异步操作的时候,使用的是最原始的回掉地狱式的写法
  • 导致代码非常不优雅,不利于阅读,不利于维护
  • 那么我们这篇文章来介绍一种相对而言更优雅的实现方式

自定义事件

  • 在 js 中使用自定义事件的方式有两种,Event 与 CustomEvent,他们最大的区别在于,Event 不能传递数据,而 CustomEvent 可以,具体大家可以自己去看看 MDN 文档,这里关注我们要实现的主题
  • 由于实现的效果是相同的,所以本文的代码可以机遇上一篇文章进行改写
  • 下面是 move 函数的改写的代码
let move = (ele, direction, target, cb) => {
    let start = parseInt(getComputedStyle(ele, null)[direction]);
    let speed = ((target - start) / Math.abs(target - start)) * 2;
    start += speed;
    ele.style[direction] = `${start}px`;

    setTimeout(() => {
      if (Math.abs(target - start) <= 2) {
        ele.style[direction] = `${target}px`;

        // cb & cb();
        ele.dispatchEvent(new CustomEvent(`myEvent-${num++}`));
      } else {
        move(ele, direction, target, cb);
      }
    }, 10);
};
  • 可以看到,上面的获取 dom 元素样式使用 getComputedStyle 和设置样式的逻辑都没有变
  • 之前的,调用回掉函数的代码换成了使用自定义事件
    • new CustomEvent 生成一个自定义事件对象
    • 通过 dispatchEvent 将事件派发出去
  • 有了事件的派发,必然有事件的监听
let ele = document.querySelector(".box");
  // move(ele, "left", 301, () => {
  //   console.log("右移 ok");
  //   move(ele, "top", 301, () => {
  //     console.log("下移 ok");
  //     move(ele, "left", 0, () => {
  //       console.log("左移 ok");
  //       move(ele, "top", 0, () => {
  //         console.log("上移 ok");
  //       });
  //     });
  //   });
  // });

  move(ele, "left", 301);

  ele.addEventListener("myEvent-1", () => {
    console.log("右移 ok");
    move(ele, "top", 301);
  });

  ele.addEventListener("myEvent-2", () => {
    console.log("下移 ok");
    move(ele, "left", 0);
  });

  ele.addEventListener("myEvent-3", () => {
    console.log("左移 ok");
    move(ele, "top", 0);
  });

  ele.addEventListener("myEvent-4", () => {
    console.log("上移 ok");
  });
  • 为了能监听到上面派发的事件,我们需要给 dom 元素绑定运动对应的事件回掉,在事件的回掉函数中,我们即可执行下一个动画的函数
  • 为了能区分派发的事件类型,我们在实例化 CustomEvent 对象的时候传入的是一个模版字符串 myEvent-${num++},其中的 num 则是一个全局变量,表示当前的事件 ID
  • 至此,我们基于自定义事件的改造已经完成

小结

  • 上面虽然解决了,前一篇文章的回掉地狱问题,并且代码看起来也是同步的写法
  • 但是上面为了区分不同的事件类型,定义了一个全局变量,难免有些不优雅
  • 那还有没有比较优雅的方式呢,下篇文章我们将使用 promise 的写法来改造这个例子

最后

  • 今天的分享就到这里了,欢迎大家在评论区里面进行讨论 👏。
  • 如果觉得文章写的不错的话,希望大家不要吝惜点赞,大家的鼓励是我分享的最大动力 🥰