likes
comments
collection
share

用发布订阅的方式处理异步算是耍流氓吗?

作者站长头像
站长
· 阅读数 59

大家好我是蜗牛,倾心于用直白的大白话来解释清楚复杂的问题的,让新手也能很好的接受。这篇文章主要围绕一道面试题 面试官:请你聊聊什么是自定义事件? 展开详细的解读

看完你能收获:

  1. js中如何自定义事件
  2. 什么是影子节点
  3. 对发布订阅的设计理念理解更加深刻

1. js中的自定义事件 Event

在原生js中,我们常见的在DOM上监听的事件有, 点击事件click, 鼠标移动事件mousemove,聚焦事件focus,失去焦点blur等等。这些是js内置的事件,事件的本质是模块对象之间的信息通信,而有时,复杂模块的之间的通信无法用基础事件来满足时,我们就可以考虑使用自定义事件了。

js中,有这么一个构造函数 Event,它可以创建一个新的事件对象

用发布订阅的方式处理异步算是耍流氓吗?

如你所见,Event() 这个构造函数可以让我们随心所欲的定义一个新的事件,在box对象上监听该look事件,再在box上 通过 dispatchEvent 派发我们定义的事件后,浏览器的控制台看到的效果

用发布订阅的方式处理异步算是耍流氓吗?

看着这个效果你是不是有一个似曾相识的感觉,这。。。不就是发布订阅嘛!好家伙,这又让我想起了面试官一边看着你的简历,一边让你手写一遍发布订阅的设计模式代码的场景,原来这个设计模式早已运用在了原生js中。

当然这里我们解释下 Event 中参数的作用 event = new Event(typeArg, eventInit);

  1. typeArg 是DOMString 类型,表示所创建事件的名称。

  2. eventInit(可选)

    对创建的事件的配置,接受以下字段:

    • "bubbles",可选,默认值为 false,表示该事件是否冒泡,true代表冒泡。
    • "cancelable",可选,默认值为 false,表示该事件能否被取消。
    • "composed",可选,默认值为 false,指示事件是否会在影子 DOM 根节点之外触发侦听器。

对于第一个参数 bubbles ,理解起来并不难,我们看效果就好

用发布订阅的方式处理异步算是耍流氓吗?

bubbles: true

用发布订阅的方式处理异步算是耍流氓吗?

bubbles: false

用发布订阅的方式处理异步算是耍流氓吗?

当我们把 bubbles 设置为 true,在 box 和父容器 wrap 上都监听自定义事件 look,再在box上发布 look 事件, wrap上的事件也因为冒泡而触发

对于第二个参数 cancelable,用法如下

用发布订阅的方式处理异步算是耍流氓吗?

这里的 console.log('在box上触发了look') 不再执行,相信你get到了

对于第三个参数 composed 比较难理解,下面我们用一个大的段落2来解释

2. 什么是影子DOM节点

影子节点和真实节点的区别就在于,影子节点是游离于DOM树之外的节点,具有良好的密封性,往往在我们需要将页面中的某一段 DOM结构封装成一个组件时发挥巨大优势。我们来看一下它的效果

用发布订阅的方式处理异步算是耍流氓吗?

渲染出来的效果是

用发布订阅的方式处理异步算是耍流氓吗?

影子DOM中的title是不受外在节点的样式影响的,如果我们要给影子DOM添加样式,可以这样写

用发布订阅的方式处理异步算是耍流氓吗?

令人兴奋的是,不仅可以这样使用,还可以用上外部的css变量

用发布订阅的方式处理异步算是耍流氓吗?

影子DOM中的文字变成了绿色

用发布订阅的方式处理异步算是耍流氓吗?

所以我们说影子节点在封装组件时作用很大,比如 bootStrap这样的UI框架的封装, 再比如我们常用的 video 标签,其实就是内置了影子DOM来完成的。

另外再解释一下 attachShadow 中的两个参数

  1. mode 模式

    • 值可以是 open 表示可以在 shadow root 元素外部通过js访问根节点

    • 或者值为 closed 拒绝从 js 外部访问关闭的 shadow root 节点

  2. delegatesFocus 焦点委托

    • 一个布尔值,当设置为 true 时,指定减轻自定义元素的聚焦性能问题行为。 当 shadow DOM 中不可聚焦的部分被点击时,让第一个可聚焦的部分成为焦点,并且 shadow host(影子主机)将提供所有可用的 :focus 样式。

第一个参数mode,为 open 和 closed 时分别的效果

在上述代码中 我们添加一行打印 console.log(root.shadowRoot);

为 open 时: 用发布订阅的方式处理异步算是耍流氓吗?

为 closed 时:

用发布订阅的方式处理异步算是耍流氓吗?

第二个参数delegatesFocus,为 true 和 false时

为了方便看效果我在影子节点中添加了一行 input

用发布订阅的方式处理异步算是耍流氓吗? 为 true 时,点击input的兄弟节点,input被聚焦 用发布订阅的方式处理异步算是耍流氓吗? 为 false 时,点击input的兄弟节点,input 不会被聚焦

用发布订阅的方式处理异步算是耍流氓吗?

了解到这里,你终于明白了影子节点是什么了,让我们回到主线任务~~~

Event 中的第三个参数 composed 分别为true 和 false 时的效果

用发布订阅的方式处理异步算是耍流氓吗?

为 true 时:

用发布订阅的方式处理异步算是耍流氓吗?

为 false 时:

用发布订阅的方式处理异步算是耍流氓吗?

也就是说,composed 用来控制自定义事件发布在影子DOM节点上时,是否还能继续传播

3. 另一个自定义事件的函数 CustomEvent

CustomEvent 接口表示由程序出于某个目的而创建的事件, 继承于基类 Event,明白 Event 之后 CustomEvent 就变得非常简单了。

用发布订阅的方式处理异步算是耍流氓吗?

用法和 Event 基本类似, 多了一个 detail 参数,可以控制当事件被订阅成功时,事件参数中定义需要的内容

4. 对异步的突发奇想

假如我们有两个异步ajax函数,fnA, fnB,需要保证函数 fnB 一定在 fnA 之后才执行,那么我们是不是可以通过控制事件的发布来控制函数的执行顺序?

用发布订阅的方式处理异步算是耍流氓吗?

这里我们用两个 setTimeout 模拟ajax的耗时请求,在 fnA 执行成功后发布一个 finish 事件到 window 上,驱使 fnB 执行,这样做即满足了需求,也没有走上回调地狱的老路,感觉非常nice呀!!!

如果封装好成为一个函数,那样会更实用一点,当然这只是一种快乐的想法,现在能用 async/await 的都用它处理了>_<.

转载自:https://juejin.cn/post/7268667397112873000
评论
请登录