第一站 - 轻松上网从此开始!

上网第一站

当前位置: > SEO >

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

时间:2017-12-12 09:37来源:segmentfault 作者:跌名 点击: 我来投稿获取授权
以下内容来自网络或网友投稿,www.swdyz.com不承担连带责任,如有侵权问题请联系我删除。投稿如果是首发请注明‘第一站首发’。如果你对本站有什么好的要求或建议。那么都非常感谢你能-联系我|版权认领
正则匹配到了只是段落内标签的结果啊,外面的没有啊。哦,对,有匹配到的索引,上次匹配到的位置加上上次处理的长度,就是一段直接文本的开始。下

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

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

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

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

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

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

  /**

  * 正文内容分段处理

  * @param {jQueryObject/HTMLElement/String} $content 要处理的正文jQ对象或HTMLElement或其对应选择器

  */

  function splitConent($content) {

  $content = $($content);

  $content.find(splitConfig.unitTag).each(function (index, item) {

  var $item = $(item),

  text = $.trim($item.text());

  if (!text) return;

  var nodes = $item[0].childNodes;

  $.each(nodes, function (i, node) {

  switch (node.nodeType) {

  case 3:

  // text 节点

  // 由于是文本节点,标签被转义了,后续再转回来

  node.data = '<' + splitConfig.wrapTag + '>' +

  node.data.replace(splitConfig.splitReg, '$&<' + splitConfig.wrapTag + '>') +

  '';

  break;

  case 1:

  // 元素节点

  var innerHtml = node.innerHTML,

  start = '',

  end = '';

  // 如果内部还有直接标签,先去掉

  var startResult = /^<\w+?>/.exec(innerHtml);

  if (startResult) {

  start = startResult[0];

  innerHtml = innerHtml.substr(start.length);

  }

  var endResult = /<\/\w+?>$/.exec(innerHtml);

  if (endResult) {

  end = endResult[0];

  innerHtml = innerHtml.substring(0, endResult.index);

  }

  // 更新内部内容

  node.innerHTML = start +

  '<' + splitConfig.wrapTag + '>' +

  innerHtml.replace(splitConfig.splitReg, '$&<' + splitConfig.wrapTag + '>') +

  '' +

  end;

  break;

  default:

  break;

  }

  });

  // 处理文本节点中被转义的html标签

  $item[0].innerHTML = $item[0].innerHTML

  .replace(new RegExp('<' + splitConfig.wrapTag + '>', 'g'), '<' + splitConfig.wrapTag + '>')

  .replace(new RegExp('</' + splitConfig.wrapTag + '>', 'g'), '');

  $item.find(splitConfig.wrapTag).addClass(splitConfig.wrapCls);

  });

  }

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

  事件处理

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

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

  原因:

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

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

  /**

  * 在页面上写入高亮样式

  */

  function createStyle() {

  if (document.getElementById('speak-light-style')) return;

  var style = document.createElement('style');

  style.id = 'speak-light-style';

  style.innerText = '.' + splitConfig.hightlightCls + '{' + splitConfig.hightStyle + '}';

  document.getElementsByTagName('head')[0].appendChild(style);

  }

  // 非正文需要朗读的标签 逗号分隔

  var speakTags = 'a, p, span, h1, h2, h3, h4, h5, h6, img, input, button';

  $(document).on('mouseenter.speak-help', speakTags, function (e) {

  var $target = $(e.target);

  // 排除段落内的

  if ($target.parents('.' + splitConfig.wrapCls).length || $target.find('.' + splitConfig.wrapCls).length) {

  return;

  }

  // 图片样式单独处理 其他样式统一处理

  if (e.target.nodeName.toLowerCase() === 'img') {

  $target.css({

  border: '2px solid #000'

  });

  } else {

  $target.addClass(splitConfig.hightlightCls);

  }

  // 开始朗读

  speakText(getText(e.target));

  }).on('mouseleave.speak-help', speakTags, function (e) {

  var $target = $(e.target);

  if ($target.find('.' + splitConfig.wrapCls).length) {

  return;

  }

  // 图片样式

  if (e.target.nodeName.toLowerCase() === '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();

  });

(责任编辑:admin)
织梦二维码生成器
顶一下
(0)
0%
踩一下
(0)
0%
------分隔线----------------------------
发布者资料
第一站编辑 查看详细资料 发送留言 加为好友 用户等级:注册会员 注册时间:2012-05-22 19:05 最后登录:2014-08-08 03:08
栏目列表
推荐内容
分享按鈕