首页
学习
活动
专区
工具
TVP
发布
精选内容/技术社群/优惠产品,尽在小程序
立即前往

网页中文本朗读功能开发实现分享

前几天完成了一个需求,在网页中完成鼠标指向哪里,就用语音读出所指的文本。如果是按钮、链接、文本输入框,则还还要给出是什么的提醒。同时针对大段的文本,不能整段的去读,要按照标点符号进行断句处理。

重点当然就是先获取到当前标签上的文本,再把文本转化成语音即可。

标签朗读

这个很简单了,只用根据当前是什么标签,给出提示即可。

还有需要朗读的标签,继续再添加即可。

然后根据标签,返回前缀文本即可。

获取完整的朗读文本就更简单了,先取标签的功能提醒,再取标签的文本即可。

文本内容优先取 其次 最后 。

这样就可以获取到一个标签的功能提醒和内容的全部带朗读文本了。

正文分隔

接下来要处理的就是正文分隔了,在这个过程中,踩了不少坑,走了不少弯路,好好记录一下。

首先准备了正文分隔的配置:

最开始想的就是直接按照正文中的分隔标点符号进行分隔就好了呀。

想法如下:

获取段落全部文本

使用 方法将正文按照标点符号分隔成小段

每个小段用标签包裹放回去即可

然而理想很丰满,现实很骨感。

两个大坑如下:

方法进行分隔,分隔后分隔字符就丢了,也就是说把原文的一些标点符号给弄丢了。

如果段落内还存在其他标签,而这个标签内部也正好存在待分隔的标点符号,那包裹分段标签时直接破换了原标签的完整性。

关于第一个问题,丢失标点的符号,考虑过逐个标点来进行和替换 分隔方法为逐个字符循环来做。

前者问题是原本一次完成的工作分成了多次,效率太低。第二种感觉效率更低了,分隔本来是很稀疏的,但是却要变成逐个字符出判断处理,更关键的是,分隔标点的位置要插入包裹标签,会导致字符串长度变化,还要处理下标索引。代码是机器跑的,或许不会觉得烦,但是我真的觉得好烦。如果这么干,或许以后哪个 AI 或者同事看到这样的代码,说不定会说 “这真是个傻 xxxx”。

第二个问题想过很多办法来补救,如先使用正则匹配捕获内容中成对的标签,对标签内部的分隔先处理一遍,然后再处理整个的。

想不明白问题二的,可参考一下待分隔的段落:

如先使用 正则,依次捕获段落内被标签包裹的内容,对标签内部的内容先处理。

但是问题又来了,这么处理的都是字符串,在 js 中都是基本类型,这些操作进行的时候都是在复制的基础上进行的,要修改到原字符串里去,还得记录下原本的开始结束位置,再将新的插进去。繁,还是繁,但是已经比之前逐个字符去遍历的好,正则捕获中本来就有了匹配的索引,直接用即可,还能接受。

但是这只是处理了段落内部标签的问题,段落内肯定还有很多文本是没有处理呢,怎么办?

正则匹配到了只是段落内标签的结果啊,外面的没有啊。哦,对,有匹配到的索引,上次匹配到的位置加上上次处理的长度,就是一段直接文本的开始。下一次匹配到的索引 - 1 就是这段直接文本的结束。这只是匹配过程中的,还有首尾要单独处理。又回到烦的老路上去了。。。

这么烦,一个段落分隔能这么繁琐,我不信!

突然想到了,有文本节点这么个东西,删繁就简嘛,正则先到边上去,直接处理段落的所有节点不就行了。

文本节点则分隔直接包裹,标签节点则对内容进行包裹,这种情况下处理的直接是 dom,更省事。

文本节点里放标签?这是在开玩笑么,是也不是。文本节点里确实只能放文本,但是我把标签直接放进去,它会自动转义,那最后再替换出来不就行了。

好了,方案终于有了,而且这个方案逻辑多简单,代码逻辑自然也不会烦。

上面代码中最后对文本节点中被转义的包裹标签替换似乎有点麻烦,但是没办法,ES5 之前 JavaScript 并不支持正则的后行断言(也就是正则表达式中 “后顾”)。所以没办法对包裹标签前后的 和 进行精准替换,只能连同标签名一起替换。

事件处理

在上面完成了文本获取和段落分隔,下面要做的就是鼠标移动上去时获取文本触发朗读即可,移开时停止朗读即可。

鼠标移动,只读一次,基于这两点原因,使用 和 事件来完成。

原因:

不冒泡,不会触发父元素的再次朗读

不重复触发,一个元素内移动时不会重复触发。

注意要把针对段落的语音处理和其他地方的分开。为什么? 因为段落是个块级元素,鼠标移入段落中的空白时,如:段落前后空白、首行缩进、末行剩余空白等,是不应该触发朗读的,如果不阻止掉,进行这些区域将直接触发整段文字的朗读,失去了我们对段落文本内分隔的意义,而且,无论什么方式转化语音都是要时间的,大段内容可能需要较长时间,影响语音输出的体验。

文本合成语音

上面我们是直接使用了 和 两个方法来触发语音的朗读和停止。

我们来看下如何实现这个两个功能。

其实现代浏览器默认已经提供了上面功能:

复制到浏览器控制台看看能不能听到声音呢?(需要 Chrome 33+、Firefox 49+ 或 IE-Edge)

利用一下两个 API 即可:

用于语音合成

: 语言 Gets and sets the language of the utterance.

: 音高 Gets and sets the pitch at which the utterance will be spoken at.

: 语速 Gets and sets the speed at which the utterance will be spoken at.

: 文本 Gets and sets the text that will be synthesised when the utterance is spoken.

: 声音 Gets and sets the voice that will be used to speak the utterance.

: 音量 Gets and sets the volume that the utterance will be spoken at.

: 单词或句子边界触发,即分隔处触发 Fired when the spoken utterance reaches a word or sentence boundary.

: 结束时触发 Fired when the utterance has finished being spoken.

: 错误时触发 Fired when an error occurs that prevents the utterance from being succesfully spoken.

: Fired when the spoken utterance reaches a named SSML "mark" tag.

: 暂停时触发 Fired when the utterance is paused part way through.

: 重新播放时触发 Fired when a paused utterance is resumed.

: 开始时触发 Fired when the utterance has begun to be spoken.

: 用于朗读

:Read only是否暂停 A Boolean that returns true if the SpeechSynthesis object is in a paused state.

:Read only是否处理中 A Boolean that returns true if the utterance queue contains as-yet-unspoken utterances.

:Read only是否朗读中 A Boolean that returns true if an utterance is currently in the process of being spoken — even if SpeechSynthesis is in a paused state.

: 声音变化时触发

: 情况待朗读队列 Removes all utterances from the utterance queue.

: 获取浏览器支持的语音包列表 Returns a list of SpeechSynthesisVoice objects representing all the available voices on the current device.

: 暂停 Puts the SpeechSynthesis object into a paused state.

: 重新开始 Puts the SpeechSynthesis object into a non-paused state: resumes it if it was already paused.

: 读合成的语音,参数必须为 的实例 Adds an utterance to the utterance queue; it will be spoken when any other utterances queued before it have been spoken.

详细 api 和说明可参考:

MDN - SpeechSynthesisUtterance

MDN - SpeechSynthesis

那么上面的两个方法可以写为:

因为语音合成本来是个异步的操作,因此在过程中进行以上处理。

现代浏览器已经内置了这个功能,两个 API 接口兼容性如下:

原文:https://blog.cdswyda.com/post/2017120914

  • 发表于:
  • 原文链接http://kuaibao.qq.com/s/20171213A059IJ00?refer=cp_1026
  • 腾讯「腾讯云开发者社区」是腾讯内容开放平台帐号(企鹅号)传播渠道之一,根据《腾讯内容开放平台服务协议》转载发布内容。
  • 如有侵权,请联系 cloudcommunity@tencent.com 删除。

扫码

添加站长 进交流群

领取专属 10元无门槛券

私享最新 技术干货

扫码加入开发者社群
领券