选中页面的文字后同步找到 textarea 内的对应文字,并选中和自动滚动到相应位置

效果图

功能截图

实现代码

  var showPdfView = document.getElementById('showPdfView') //选择的文本
  showPdfView.onclick = function (e) {
   
    var select_str = getSelectionField(e)
    if (select_str === ''){
   
      return
    }
    var textarea = document.getElementById('showPdfViewHtml') //最后被标记的文本域
    if (textarea.value.indexOf(select_str) !== -1){
   

      //    当前选中的文字父节点
      var parent_node = $(window.getSelection().getRangeAt(0).commonAncestorContainer.parentElement)

      parent_node.addClass('select') //标记当前选中的文字所在的节点

      var node_arr = []

      ergodic_ndoe(showPdfView) //遍历所有节点,找到和用户选中文字匹配的所有节点

      //递归遍历元素
      function ergodic_ndoe(node) {
   
        if(node.nodeType === 1){
         //判断是不是元素节点
          if (node.children.length === 0){
    //            当前节点的子节点为0个时,判断节点的文本内容是否符合用户所选的字符
            if (node.innerHTML.indexOf(select_str) !== -1){
   
              var index= -2;//开始查询的位置
              var re = new RegExp(select_str, 'g')
              var arr = node.innerHTML.match(re);
              if (arr.length>1){
   
//                选中的元素所在的位置
                var position = 0
//                当前选中的节点在文本中的偏移量
                var anchorOffset = window.getSelection().anchorOffset

                for (var i = 0;i<arr.length;i++){
   
                  index = node.innerHTML.indexOf(select_str, index) + select_str.length;//从下标index开始向后查询
                  if (index === anchorOffset + select_str.length){
    //当前匹配的字符串和选中的字符串在当前元素内的偏移量做对比
                    position = i
                  }
                  else if (index === anchorOffset){
    //客户从右往左选时偏移量不用加上选中的字符长度
                    position = i
                  }
                }
                node_arr.push({
   
                  el_select: node, //节点
                  this_all_number: arr.length, //当前节点符合选中的字符的总个数
                  position: position //字符在当前节点的位置
                })
              }
              else {
   
                node_arr.push({
   
                  el_select: node,
                  this_all_number: 1,
                  position: 0
                })
              }
            }
          }
          else {
     //当前节点的子节点不为零,继续往下找
            for (var i = 0;i<node.children.length;i++){
   
              ergodic_ndoe(node.children[i])
            }
          }
        }
      }

      var sign = 0 //选中的字符为第几个字符
      for (var j = 0;j< node_arr.length;j++){
   
        if ($(node_arr[j].el_select).hasClass('select')){
   
          sign += node_arr[j].position + 1 //统计一直到选中的文字之前还有多少个相同的文字,以确认自己的位置
          $(node_arr[j].el_select).removeClass('select')
          break;
        }
        else {
   
          sign += node_arr[j].this_all_number
        }
      }

      //右边的对应位置
      var index2 = -2;//开始查询的位置
      var re_r = new RegExp(select_str, 'g')
      var arr_r = textarea.value.match(re_r); //用正则匹配文本域内选中的所有字符

//      判断当前字符在当前节点是否只有一个
      if (arr_r && arr_r.length > 1){
   
        for (var i = 0;i<arr_r.length;i++){
   
          index2 = textarea.value.indexOf(select_str, index2) + select_str.length;//从下标index开始向后查询

          //当前字符的位置和选中的字符一致
          if ((i+1) === sign){
   
            var line_break_str = textarea.value.substring(0,index2);  //截取开始到选中的字符为止
            var line_break_end = textarea.value.substr(index2); //截取选中的字符开始到末尾
            textarea.value = line_break_str //将前半段赋值给文本域
            h1 = textarea.scrollHeight //获取此时的文本域的滚动条高度
            textarea.value = line_break_str + line_break_end //还原文本域的内容
            textarea.scrollTop = h1 - 250 //给滚动条赋值,控制选中的文字到中间,250是当前文本域的高度的一半

            textarea.selectionStart = index2 - select_str.length;
            textarea.selectionEnd = index2
            break;
          }
        }
      }


//     当前字符在当前节点只有一个时,直接定位和选中
      if (index2 === -2){
   
         line_break_str = textarea.value.substring(0,textarea.value.indexOf(select_str)); //截取开始到选中的字符为止
         line_break_end = textarea.value.substr(textarea.value.indexOf(select_str)); //截取选中的字符开始到末尾
        textarea.value = line_break_str //将前半段赋值给文本域
        var h1 = textarea.scrollHeight //获取此时的文本域的滚动条高度
        textarea.value = line_break_str + line_break_end //还原文本域的内容
        textarea.scrollTop = h1 - 250 //给滚动条赋值,控制选中的文字到中间,250是当前文本域的高度的一半

        textarea.selectionStart = textarea.value.indexOf(select_str); //文本域的选中开始位置
        textarea.selectionEnd = textarea.value.indexOf(select_str) + select_str.length  //文本域的选中结束位置
      }

      textarea.focus(); //给文本域焦点

      //用行数计算滚动条位置(感觉不如上面的方法准确)
//      var line_break_arr = line_break_str.match(/\r|\n/g);  //前面一段的换行符数量
//      textarea.scrollTop = line_break_arr.length * 14 //行数乘以文字大小得到滚动条高度
    }
    else {
   
      alert('没有找到匹配项,请选中一个连续的字词')
    }
  }

//  获取选中的文字
  function getSelectionField(e) {
   
    var selection = '';
    selection = getIeSelection(e);
    if (selection == '') {
   
      selection = getFireFoxSelection(e);
    }
    return selection.replace(/(^\s*)|(\s*$)/g, ""); //  去掉前後空格
  }

  //  获取选中的文字兼容
  function getIeSelection() {
   
    if (window.getSelection) {
   
      return window.getSelection().toString();
    }
    else if (document.getSelection) {
   
      return document.getSelection();
    } else if (document.selection) {
   
      return document.selection.createRange().text;
    }
  }

  //  获取选中的文字兼容
  function getFireFoxSelection(e) {
   

    if (e.selectionStart != undefined && e.selectionEnd != undefined) {
   
      var start = e.selectionStart;
      var end = e.selectionEnd;

      return e.value.substring(start, end);
    } else {
   
      return "";
    }
  }

model

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<table class="tblborder" cellspacing="0" cellpadding="0" style="width: 100%;" border="0">
    <tbody>
    <tr>
        <td>
            <form name="form" id="myform" method="post" action="">
                <input type="hidden" value="1" name="direction">
                <input type="hidden" value="2" name="hear_foot">
                <input type="hidden" value="0,0" name="pdf_header_or_footer">
                <input type="hidden" value="486" name="tid">
                <table cellspacing="0" cellpadding="0" width="100%" border="0">
                    <tbody>
                    <tr class="firstalt">
                        <td colspan="3">
                        </td><td colspan="5">
                        <div id="fixedShow">
                            <table width="100%" border="0" cellspacing="0" cellpadding="0">
                                <tbody>
                                <tr class="tbti">
                                    <td width="100%" align="center" style="padding-left:10px;line-height: 40px;">
                                        <button type="button" class="layui-btn layui-btn-sm" onclick="export_pdf()">導出PDF</button>
                                        &nbsp;&nbsp;&nbsp;&nbsp;
                                    </td>
                                </tr>
                                </tbody>
                            </table>
                        </div>
                    </td>
                    </tr>
                    <tr class=""><td colspan="6">&nbsp;</td></tr>
                    <tr class="">
                        <td style="width:1%">&nbsp;</td>
                        <td style="width:47%" align="left" valign="top">
                            <div id="showPdfView" class="left"><h2 style="text-align: center;"><span style="font-size: 8px;"><strong><span style="font-family: 黑体;"><span style="font-family: 黑体; font-size: 10px;"></span><htmlpageheader name="myHeader1"></htmlpageheader></span></strong></span></h2><h2 style="text-align: center;"><span style="
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值