欢迎来到三一文库! | 帮助中心 三一文库31doc.com 一个上传文档投稿赚钱的网站
三一文库
全部分类
  • 研究报告>
  • 工作总结>
  • 合同范本>
  • 心得体会>
  • 工作报告>
  • 党团相关>
  • 幼儿/小学教育>
  • 高等教育>
  • 经济/贸易/财会>
  • 建筑/环境>
  • 金融/证券>
  • 医学/心理学>
  • ImageVerifierCode 换一换
    首页 三一文库 > 资源分类 > DOC文档下载  

    网页中文本朗读功能开发实现.doc

    • 资源ID:14604230       资源大小:262KB        全文页数:10页
    • 资源格式: DOC        下载积分:4
    快捷下载 游客一键下载
    会员登录下载
    微信登录下载
    三方登录下载: 微信开放平台登录 QQ登录   微博登录  
    二维码
    微信扫一扫登录
    下载资源需要4
    邮箱/手机:
    温馨提示:
    用户名和密码都是您填写的邮箱或者手机号,方便查询和重复下载(系统自动生成)
    支付方式: 支付宝    微信支付   
    验证码:   换一换

    加入VIP免费专享
     
    账号:
    密码:
    验证码:   换一换
      忘记密码?
        
    友情提示
    2、PDF文件下载后,可能会被浏览器默认打开,此种情况可以点击浏览器菜单,保存网页到桌面,就可以正常下载了。
    3、本站不支持迅雷下载,请使用电脑自带的IE浏览器,或者360浏览器、谷歌浏览器下载即可。
    4、本站资源下载后的文档和图纸-无水印,预览文档经过压缩,下载后原文更清晰。
    5、试题试卷类文档,如果标题没有明确说明有答案则都视为没有答案,请知晓。

    网页中文本朗读功能开发实现.doc

    前几天完成了一个需求,在网页中完成鼠标指向哪里,就用语音读出所指的文本。 如果是按钮、链接、文本输入框,则还还要给出是什么的提醒。同时针对大段的文 本,不能整段的去读,要按照标点符号进行断句处理。重点当然就是先获取到当前标签上的文本,再把文本转化成语音即可。标签朗读这个很简单了,只用根据当前是什么标签,给出提示即可。1./标签朗读文本2.var tagTextConfig = 3.'a':'链接',4.'inputtext':'文本输入框',5.'inputpassword':'密码输入框',6.'button':'按钮',7.8.'img':'图片;还有需要朗读的标签,继续再添加即可。然后根据标签,返回前缀文本即可。1./*2.*获取标签朗读文本3.* param HTMLEIement el要处理的 HTMLEIement4.* returns String朗读文本5.*/6.function getTagText(el) 7.if (!el) return ''8.var tagName =;9./处理in put等多属性元素10.switch (tagName) 11.case 'input' :12.tagName += ''+ el.type +''13.break;14.default :15.break;16.17./标签的功能提醒和作用应该有间隔,因此在最后加入一个空格18.return (tagTextConfigtagName |”)+ ''19.获取完整的朗读文本就更简单了,先取标签的功能提醒,再取标签的文本即可。文本内容优先取title 其次alt最后innerText1./*2.*获取完整朗读文本3.* param HTMLEIement el要处理的 HTMLEIement4.* returns String朗读文本5.*/6.function getText(el) 7.if (!el) return ''8.return getTagText(el) + (el.title | el.alt | el.innerText |'');9.这样就可以获取到一个标签的功能提醒和内容的全部带朗读文本了正文分隔接下来要处理的就是正文分隔了,在这个过程中,踩了不少坑,走了不少弯路,好好记录一下。首先准备了正文分隔的配置:1./正文拆分配置2.var splitConfig = 3./内容分段标签名称4.unitTag: 'p',5./正文中分隔正则表达式6.splitReg:/,;,;。/ g,7./包裹标签名8.wrapTag: 'label',9./包裹标签类名10.wrapCls: 'speak-lable' ,11./高亮样式名和样式12.hightlightCIs:'speak-help-hightlight',13.hightStyle:'background: #000!important; color: #fff!important'14.;最开始想的就是直接按照正文中的分隔标点符号进行分隔就好了呀。想法如下:1. 获取段落全部文本2. 使用split(分隔正则表达式)方法将正文按照标点符号分隔成小段3. 每个小段用标签包裹放回去即可然而理想很丰满,现实很骨感。两个大坑如下:1. split方法进行分隔,分隔后分隔字符就丢了,也就是说把原文的一些标点符号 给弄丢了。2. 如果段落内还存在其他标签,而这个标签内部也正好存在待分隔的标点符号,那包裹分段标签时直接破换了原标签的完整性。关于第一个问题,丢失标点的符号,考虑过逐个标点来进行和替换split 分隔方法为逐个字符循环来做。前者问题是原本一次完成的工作分成了多次,效率太低。第二种感觉效率更低了, 分隔本来是很稀疏的,但是却要变成逐个字符出判断处理,更关键的是,分隔标点 的位置要插入包裹标签,会导致字符串长度变化,还要处理下标索引。代码是机器 跑的,或许不会觉得烦,但是我真的觉得好烦。如果这么干,或许以后哪个AI或者同事看到这样的代码,说不定会说“这真是个傻XXXX ”。第二个问题想过很多办法来补救,如先使用正则匹配捕获内容中成对的标签,对标签内部的分隔先处理一遍,然后再处理整个的。想不明白问题二的,可参考一下待分隔的段落:1.<卩>这是一段测试文本,这里有个链接。 <a>您好,可以点击此处进行跳转 </a>还有其他内容其他内容容其他内容容其他内容,容其他内容。</p>如先使用/v(w+?)>)(.+?)<V2(?=>)/g正则,依次捕获段落内被标签包裹的内容,对标签内部的内容先处理。但是问题又来了,这么处理的都是字符串,在js中都是基本类型,这些操作进行的时候都是在复制的基础上进行的,要修改到原字符串里去,还得记录下原本的开始 结束位置,再将新的插进去。繁,还是繁,但是已经比之前逐个字符去遍历的好, 正则捕获中本来就有了匹配的索引,直接用即可,还能接受。但是这只是处理了段落内部标签的问题,段落内肯定还有很多文本是没有处理呢,怎么办?正则匹配到了只是段落内标签的结果啊, 外面的没有啊。哦,对,有匹配到的索引, 上次匹配到的位置加上上次处理的长度,就是一段直接文本的开始。下一次匹配到 的索引-1就是这段直接文本的结束。这只是匹配过程中的,还有首尾要单独处理。又回到烦的老路上去了。这么烦,一个段落分隔能这么繁琐,我不信!突然想到了,有文本节点这么个东西,删繁就简嘛,正则先到边上去,直接处理段 落的所有节点不就行了。文本节点则分隔直接包裹,标签节点则对内容进行包裹,这种情况下处理的直接是dom,更省事。文本节点里放标签?这是在开玩笑么,是也不是。文本节点里确实只能放文本,但 是我把标签直接放进去,它会自动转义,那最后再替换出来不就行了。好了,方案终于有了,而且这个方案逻辑多简单,代码逻辑自然也不会烦。1./*2.*正文内容分段处理3.* param jQueryObject/HTMLEIement/String$content要处理的正文jQ对象或HTMLEIemen或其对应选择器4.*/5.function splitConent($content) 6.$content = $($content);7.$content.find(splitConfig.unitTag).each(function (index, item) 8.var $item = $(item),9.text = $.trim($item.text();10.if (!text)return ;11.var nodes = $item O.childNodes;12.$.each(nodes, function (i, node) 13.switch (node.nodeType) 14.case 3:15./ text 节点16./由于是文本节点,标签被转义了,后续再转回来17.node.data ='<' + splitConfig.wrapTag +'>' +18.,'</'+ splitConfig.wrapTag +'>$&<' +splitConfig.wrapTag +'>' ) +19.'</'+ splitConfig.wrapTag +'>'20.break;21.case 1:22./ 元素节点23.var innerHtml = node.innerHTML,24.start ='',25.end =''26./如果内部还有直接标签,先去掉27.var startResult =/A<w+?>/ .exec(innerHtml);28.if (startResult) 29.start = startResult0;30.innerHtml = innerHtml.substr(start.length);31.32.var endResult =/</w+?>$/. exec(innerHtml);33.if (endResult) 34.end = endResult 0;35.innerHtml = innerHtml.substring(0, endResult.index);36.37./更新内部内容38.node.innerHTML = start +39.'<'+ splitConfig.wrapTag +'>' +40.innerHtml.replace(splitConfig.splitReg,+ splitConfig.wrapTag +'>' ) +'</' + splitConfig.wrapTag +'>$&<'41.'</'+ splitConfig.wrapTag +'>' +42.end;43.break;44.default :45.break;46.47.);48./处理文本节点中被转义的 html标签49.$item 0.innerHTML = $item 0.innerHTML50.replace( newRegExp '&lt;'+ splitConfig.wrapTag+ '&gt;','g' ), '<'+ splitConfig.wrapTag+ '>')51.replace( new RegExp '&It;/'+ splitConfig.wrapTag +'&gt;''>');,'g' ), '</'+ splitConfig.wrapTag +52.$item.find(splitConfig.wrapTag).addClass(splitConfig.wrapCls);53.);54.上面代码中最后对文本节点中被转义的包裹标签替换似乎有点麻烦,但是没办法,ES5之前JavaScript并不支持正则的后行断言(也就是正则表达式中“后顾”)所以没办法对包裹标签前后的&It;和&gt;进行精准替换,只能连同标签名一起替换。事件处理在上面完成了文本获取和段落分隔,下面要做的就是鼠标移动上去时获取文本触发朗读即可,移开时停止朗读即可。鼠标移动,只读一次,基于这两点原因,使用mouseenter和 mouseleave事件来完成。原因:1. 不冒泡,不会触发父元素的再次朗读2. 不重复触发,一个元素内移动时不会重复触发1./*2.*在页面上写入咼亮样式3.*/4.function createStyle() 5.if (document.getElementByld( 'speak-light-style') return ;6.var style = document.createElement('style' );7.style.id ='speak-light-style'8.style.innerText ='.'+ splitConfig.hightlightCIs +''+ splitConfig.hightStyle +''9.document.getElementsByTagName( 'head' ) 0.appendChild(style);10.11./非正文需要朗读的标签逗号分隔12.var speakTags ='a, p, span, h1, h2, h3, h4, h5, h6, img, input, button'13.$(document).on( 'mouseenter.speak-help' , speakTags, function (e) 14.var $target = $(e.target);15./排除段落内的16.if ($target.parents('.'+ splitConfig.wrapCls).length | $target.find('.'+ splitConfig.wrapCls).length) 17.return ;18.19./图片样式单独处理其他样式统一处理20.if ( = 'img' ) 21.$target.css(22.border: '2px solid #000'23.);24. else 25.$target.addClass(splitConfig.hightlightCls);26.27.28.29.30.31.32.33.34.35.36.37.38.39.40.41.42.43.44.45.46.47.48.49.50.51.52.53.54./开始朗读speakText(getText(e.target);).on( 'mouseleave.speak-help' , speakTags, function (e) var $target = $(e.target);if ($target.find( '.'+ splitConfig.wrapCls).length) return ;/图片样式if ( = 'img' ) $target.css(border: 'none'); else $target.removeClass(splitConfig.hightlightCls);/停止语音stopSpeak(););/段落内文本朗读$(document).on( 'mouseenter.speak-help' , '.'+ splitConfig.wrapCls, function (e) $( this ).addClass(splitConfig.hightlightCls);/开始朗读speakText(getText( this );).on( 'mouseleave.speak-help' , '.'+ splitConfig.wrapCls, function (e) $( this ).removeClass(splitConfig.hightlightCls);/停止语音stopSpeak(););注意要把针对段落的语音处理和其他地方的分开。为什么? 因为段落是个块级元素, 鼠标移入段落中的空白时,如:段落前后空白、首行缩进、末行剩余空白等,是不 应该触发朗读的,如果不阻止掉,进行这些区域将直接触发整段文字的朗读,失去 了我们对段落文本内分隔的意义,而且,无论什么方式转化语音都是要时间的,大 段内容可能需要较长时间,影响语音输出的体验。文本合成语音上面我们是直接使用了speakText(text)禾口 stopSpeak()两个方法来触发语音的朗读和停止。我们来看下如何实现这个两个功能。其实现代浏览器默认已经提供了上面功能:1.2.3.var speechSU = new window. SpeechSynthesisUtterance (); speechSU.text ='你好,世界!'复制到浏览器控制台看看能不能听到声音呢?(需要Chrome 33+、Firefox 49+ 或IE-Edge)利用一下两个API即可:SpeechS yn thesisUttera nee用于语音合成lang : 语言 Gets and sets the Ianguage of the utteranee.pitch : 音高 Gets and sets the pitch at which the utteranee will be spoken at. rate : 语速 Gets and sets the speed at which the utteranee will be spoken at. text : 文本 Gets and sets the text that will be synthesised when the utteranee is spoke n.voice :声音 Gets and sets the voice that will be used to speak the utteranee. volume : 音量 Gets and sets the volume that the utteranee will be spoken at. on bou ndary :单词或句子边界触发,即分隔处触发 Fired whe n the spoken uttera nee reaches a word or sentence boun dary.onend : 结束时触发 Fired when the utteranee has finished being spoken.on error : 错误时触发 Fired whe n an error occurs that preve nts the uttera nee from being succesfully spoke n.onmark: Fired when the spoken utteranee reaches a named SSML "mark" tag. on pause : 暂停时触发 Fired whe n the uttera nee is paused part way through. on resume : 重新播放时触发 Fired whe n a paused uttera nee is resumed.on start : 开始时触发 Fired whe n the uttera nee has begu n to be spoke n.SpeechS yn thesis用于朗读paused : Read only 是否暂停 A Boolean that returns true if theSpeechS yn thesis object is in a paused state.pending : Read only 是否处理中 A Boolean that returns true if the utteranee queue contains as-yet- un spoke n uttera nces.speaking : Read only 是否朗读中 A Boolean that returns true if an utteranee is currently in the process of being spoken even if SpeechSynthesis is in a paused state.onv oicescha nged : 声音变化时触发can cel(): 情况待朗读队歹U Removes all uttera nces from the uttera nee queue.getVoices():获取浏览器支持的语音包列表Returns a list ofSpeechSynthesisVoice objects representing all the available voices on the curre nt device.pause(): 暂停 Puts the SpeechSynthesis object into a paused state. resume(): 重新开始 Puts the SpeechSynthesis object into a non-paused state: resumes it if it was already paused.speak():读合成的语音,参数必须为SpeechSynthesisUtteranee 的实例 Adds an utterance to the utterance queue; it will be spoken when any other uttera nces queued before it have bee n spoke n.详细api和说明可参考:MDN - SpeechSy nthesisUttera nceMDN - SpeechSy nthesis那么上面的两个方法可以写为:1.var speaker = newwindow. SpeechSynthesisUtterance ();2.var speakTimer,3.stopTimer;4./开始朗读5.function speakText(text) 6.clearTimeout(speakTimer);7.8.speakTimer = setTimeout( function () 9.speaker.text = text;10.11., 200);12.13./停止朗读14.function stopSpeak() 15.clearTimeout(stopTimer);16.clearTimeout(speakTimer);17.stopTimer = setTimeout( function () 18.19., 20);20.因为语音合成本来是个异步的操作,因此在过程中进行以上处理。现代浏览器已经内置了这个功能,两个API接口兼容性如下:cdswyda -网页文本朗读实现-github如果要兼容其他浏览器或者需要一种完美兼容的解决方案,可能就需要服务端完成了,根据给定文本,返回相应语音即可,百度语音 就提供这样的服务。 cdswyda - 网页文本朗读实现 -github (/show/tree/master/demo/speaker ) cdswyda - 网页文本朗读实现 -demo (/demo/speaker/ )

    注意事项

    本文(网页中文本朗读功能开发实现.doc)为本站会员(scccc)主动上传,三一文库仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对上载内容本身不做任何修改或编辑。 若此文所含内容侵犯了您的版权或隐私,请立即通知三一文库(点击联系客服),我们立即给予删除!

    温馨提示:如果因为网速或其他原因下载失败请重新下载,重复下载不扣分。




    经营许可证编号:宁ICP备18001539号-1

    三一文库
    收起
    展开