onscroll、compositionstart和compositionend事件浅谈

1,125 阅读4分钟

前言

最近一段时间一直处于不停改Bug的状态(结果是bug越改越多。。),本文分享一下在这期间学到的一些新的知识。

scroll

下面来看一个dom结构

<div id="parent">
 <Modal>
</div>

下面简单描述一下这个和scroll事件有关的bug的场景。

父元素parent是一个块级元素,在其上面绑定scroll事件,随着鼠标滑轮的滚动,parent的UI会发生变化。

子元素是一个Modal组件,有自己的逻辑。现在发生了一个问题,当打开子元素的Modal弹窗后,对着Modal内部的元素做了一系列交互之后,发现parent元素的UI发生了变化,通过debug之后,查出原因,当子元素Modal内部出现滚动条,鼠标滑轮进行滚动,触发了parent元素的scroll事件,导致parent的UI发生了变化。

一般情况下,这种问题我们只要阻止子元素的事件进行冒泡,就可以解决这个问题。但比较特殊的就在于这个scroll事件。恰好最近听了一位同事的技术分享,讲的就是这个scroll事件,scroll事件最特殊的一点在于,它不能阻止事件冒泡,或者说scroll本身就没有冒泡机制。

由于JS事件的冒泡机制,触发事件的元素会逐渐向上层传递,我们可以在document中收到所有的事件触发。所以当我们的要写一套和js事件相关的库的话,就可以将所有的事件放到最上层的document中进行处理,这种方式叫做事件委托,React的事件就是这么处理的。但是有些事件比较特殊,比如我们这次提到的scroll,甚至于React对scroll事件的代理都是放到了捕获阶段。

不知道有没有人发现上述的逻辑似乎有点问题,scroll比较特殊,他没有冒泡机制,也不能被取消,那么子元素的滚动,其实是不能传到parent元素的,所以按道理正常情况这个bug是不会产生的。

其实这个bug是很好解决的,我最后是在Modal打开的状态下直接禁用掉了parent元素的onScroll方法,但是这种现象值得深挖一下背后的逻辑。

这里我有两种猜测,一是我们系统中使用的是React的事件体系,并非原生的JS事件,所以导致了这个问题。 二是Modal组件使用了react-modal这个库,这个组件比较特殊导致的。

因为时间问题,这两种猜测我没有深入研究,后续有时间会继续跟进。

scroll事件类似的还有blurfocus等事件

compositionstarcompositionend

这两个事件如果了解过JS监听中文输入法这方面知识的程序员可能知道。

先来一段MDN的定义

文本合成系统如 input method editor(即输入法编辑器)开始新的输入合成时会触发 compositionstart 事件。

当文本段落的组成完成或取消时, compositionend 事件将被触发 (具有特殊字符的触发, 需要一系列键和其他输入, 如语音识别或移动中的字词建议)。

简单来说,就是使用中文输入法的时候,当开始输入汉字时触发 compositionstar,当输入完成时触发compositionend,可以不管这期间用户输入多少个拼音。

这两个事件本身没什么好说的,用到的可以搭配input或者change事件来实现相关业务。

但是最近遇到个比较特殊的使用场景,那就是移动端输入的英文智能联想(我一直是小米手机,从来不知道还有这个功能,听其他人说,大部分手机输入法都是默认开启的)。英文的智能联想开启之后,会导致英文输入变成了中文输入法一样的场景。一般情况下似乎也没什么问题。但是我们项目中使用的draft-js这个富文本的组件就在英文智能联想的场景中出现了问题。

这个组件的onChange方法,在英文智能联想输入的情况下,如果将文本全部清空,onChange方法就不会触发,导致用户无法将自己输入的内容一次性删除。

定位到draft-js之后,发现最新版本是没有这个bug的,然后开始进行版本升级,这里主要提醒一下,如果有这种对输入文本进行比较复杂的数据处理的功能的话,最好别忘了输入法英文智能联想这个功能。

总结

以上是对工作中遇到的一些知识的总结,希望以后再遇到相同的问题可以及时定位处理。