美文网首页
基于getClientRects()实现行内元素多行文本展开收起

基于getClientRects()实现行内元素多行文本展开收起

作者: smebs | 来源:发表于2021-04-22 11:19 被阅读0次

    一般的省略实现方式

    经常会遇到多行文本省略变成...的形式的开发要求,并且基于用户体验的角度出发,还需要对于文本有对应展开与收起的操作按钮。
    1.使用css属性

    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    

    或者

    overflow: hidden;
    display: -webkit-box;
    -webkit-box-orient: vertical;
    -webkit-line-clamp: 3;
    

    都只是实现了...的省略功能,达不到需求的目的。
    2.通过js都是判断固定的长度(但是div或者span往往长度不固定)切割省略,总是会有一个字符或者两个字符留白或者部分机型刚好换行的,没有很好实现需求。


    通过js切割固定的长度.png

    基于getClientRects()的实现方式

    1.getClientRects()的作用就是获取元素占据页面的所有矩形区域。

    var rect = document.getElementById('#rect');
    console.log(rect)
    //bottom: 58 height: 19 left: 20 right: 330.578125 top: 39 width: 310.578125 x: 20 y: 39
    

    返回值是ClientRect对象集合,该对象是与该元素相关的CSS边框。每个ClientRect对象包含一组描述该边框的只读属性——left、top、right和bottom,单位为像素,这些属性值是相对于视口的top-left的。即使当表格的标题在表格的边框外面,该标题仍会被计算在内。

    起初,微软打算让这个方法给文本的每一行都返回一个TextRectangle,但是,CSSOM工作草案规定它应该给每个边框返回一个ClientRect。因此,对于行内元素这两个定义是相同的,但是对于块级元素,Mozilla只会返回一个矩形。(译者注:对于行内元素,元素内部的每一行都会有一个边框;对于块级元素,如果里面没有其他元素,一整块元素只有一个边框)。

    2.行内元素通过getClientRects()就能获取到当前文本多少行,只要通过遍历,每次减少1个长度(br标签减少5),不断计算是否是所需要的行数即可(例如文本5行,我需要3行省略,只要让对于的span刚好是3行就可以,这样就得到一个省略的文本了)
    基于jQuery的方法实现如下:
    html:

    <!DOCTYPE html>
    <html lang="en">
      <head>
        <meta charset="UTF-8" />
        <meta http-equiv="X-UA-Compatible" content="IE=edge" />
        <meta name="viewport" content="width=device-width, initial-scale=1.0" />
        <title>完美版本的展开收起...</title>
        <style>
          *{margin: 0;
          padding: 0;}
          div {
            width: 700px;
            height: auto;
            font-size: 14px;
            color: #333;
            background-color: #fafafa;
            padding: 20px;
          }
          span.text-fold {
            display: inline;
            color: #4293f4;
            cursor: pointer;
          }
          span.col-333 {
            color: #333;
            font-size: 14px;
            line-height: 20px;
          }
        </style>
      </head>
      <body>
        <div>
          <span class="">春 ——朱自清:<br /></span>
          <span class="break-word col-333" id="txt" style="display: inline;"
            >&nbsp;&nbsp;&nbsp;&nbsp;盼望着,盼望着,东风来了,春天的脚步近了。<br>
            一切都像刚睡醒的样子,欣欣然张开了眼。山朗润起来了,水涨起来了,太阳的脸红起来了。<br>
            &nbsp;&nbsp;&nbsp;&nbsp;小草偷偷地从土地里钻出来,嫩嫩的,绿绿的。园子里,田野里,瞧去,一大片一大片满是的。坐着,躺着,打两个滚,踢几脚球,赛几趟跑,捉几回迷藏。风轻悄悄的,草软绵绵的。<br>
            &nbsp;&nbsp;&nbsp;&nbsp;桃树,杏树,梨树,你不让我,我不让你,都开满了花赶趟儿。红的像火,粉的像霞,白的像雪。花里带着甜味;闭了眼,树上仿佛已经满是桃儿,杏儿,梨儿。花下成千成百的蜜蜂嗡嗡的闹着,大小的蝴蝶飞来飞去。野花遍地是:杂样儿,有名字的,没名字的,散在草丛里像眼睛像星星,还眨呀眨的。<br>
            &nbsp;&nbsp;&nbsp;&nbsp;“吹面不寒杨柳风”,不错的,像母亲的手抚摸着你,风里带着些新翻的泥土的气息,混着青草味儿,还有各种花的香,都在微微润湿的空气里酝酿。鸟儿将巢安在繁花嫩叶当中,高兴起来了,呼朋引伴的卖弄清脆的歌喉,唱出婉转的曲子,跟清风流水应和着。牛背上牧童的短笛,这时候也成天嘹亮的响着。<br>
            &nbsp;&nbsp;&nbsp;&nbsp;雨是最寻常的,一下就是三两天。可别恼。看,像牛毛,像花针,像细丝,密密地斜织着,人家屋顶上全笼着一层薄烟。树叶却绿得发亮,小草也青得逼你的眼。傍晚时候,上灯了,一点点黄晕的光,烘托出一片安静而和平的夜。在乡下,小路上,石桥边,有撑着伞慢慢走着的人,地里还有工作的农民,披着蓑戴着笠。他们的房屋稀稀疏疏的,在雨里静默着。<br>
            &nbsp;&nbsp;&nbsp;&nbsp;天上的风筝渐渐多了,地上的孩子也多了。城里乡下,家家户户,老老小小,也赶趟似的,一个个都出来了。舒活舒活筋骨,抖擞抖擞精神,各做各的一份事儿去。
            &nbsp;&nbsp;&nbsp;&nbsp;“一年之计在于春”,刚起头儿,有的是功夫,有的是希望。<br>
            &nbsp;&nbsp;&nbsp;&nbsp;春天像刚落地的娃娃,从头到脚都是新的,它生长着。<br>
            &nbsp;&nbsp;&nbsp;&nbsp;春天像小姑娘,花枝招展的,笑着走着。<br>
            &nbsp;&nbsp;&nbsp;&nbsp;春天像健壮的青年,有铁一般的胳膊和腰脚,领着我们向前去。</span
          >
          <script src="http://libs.baidu.com/jquery/1.11.1/jquery.min.js"></script>
          <script src="../js/rectOmitText.js"></script>
          <script>
            $(function(){
              $('#txt').rectOmitText({
                line: 5,
                foldText: '隐藏',
                unfoldText: '更多',
                foldClass: 'text-fold'
              });
            })
          </script>
        </div>
      </body>
    </html>
    
    

    基于jquery实现的rectOmitText.js:

    /*
     * getClientRects()只是支持行内元素,非行内元素不支持该方法
     * unfoldText 展开文本
     * foldText 收起文本
     * unfoldClass 展开类名
     * foldClass 收起类名
     * line 多少行省略
     * color 默认样式颜色
     */
    
    (function ($) {
      $.fn.rectOmitText = function (options) {
        if ($(this).css("display") != "inline") {
          console.warn(
            "该方法不支持非行内(inline)元素展开收起以及省略,!请把对应的元素转为inline元素"
          );
          return false;
        }
    
        var defaluts = {
          unfoldText: "展开",
          foldText: "收起",
          unfoldClass: "",
          foldClass: "",
          line: 1,
          color: "style='color: #2a68c9;'",
        };
        
        var opt = $.extend(defaluts, options);
        var txtHtml = $(this).html(); //所有文本
        var omitHtml = $(this).html(); //省略文本
        var rect = $(this)[0].getClientRects(); //获取元素占据页面的所有矩形区域
        console.log(rect)
        var line = getLineLen(rect); //文本真实的行数
        //展开显示文本
        var unfold = opt.unfoldClass
          ? "<span>... </span><span class='rect-unfold " +
            opt.unfoldClass +
            "'>" +
            opt.unfoldText +
            "</span>"
          : "<span>... </span><span " +
            opt.color +
            " class='rect-unfold " +
            opt.unfoldClass +
            "'>" +
            opt.unfoldText +
            "</span>";
        //收起显示文本
        var fold = opt.foldClass
          ? "<span class='rect-fold " +
            opt.foldClass +
            "'>" +
            opt.foldText +
            "</span>"
          : "<span " +
            opt.color +
            "class='rect-fold " +
            opt.foldClass +
            "'>" +
            opt.foldText +
            "</span>";
    
        if (line && line == 1) {
          console.warn("标签文本内容只有一行,不作省略!");
          return false;
        }
    
        if (opt.line >= line) {
          console.warn("传入的省略行数大于文本行数,不作省略");
          return false;
        }
    
        //行数大于5行,显示... 展开按钮
        while (line > opt.line) {
          var step = 1;
          if (/<br\/>$/.test(omitHtml)) {
            //回退的时候,如果碰到换行要整体替换
            step = 5;
          }
    
          //每次减少文本数组最后以为参数(br标签直接减少整个br标签的长度)
          omitHtml = omitHtml.slice(0, -step);
          txt.innerHTML = omitHtml + unfold;
    
          //更新行数
          line = getLineLen($(this)[0].getClientRects());
          if (omitHtml.length <= 0) {
            //强制停止循环
            break;
          }
        }
    
        //展开点击
        $("#txt").on("click", "span.rect-unfold", function () {
          $("#txt").html(txtHtml + fold);
        });
    
        //收起点击
        $("#txt").on("click", "span.rect-fold", function () {
          $("#txt").html(omitHtml + unfold);
        });
    
        function getLineLen(arr) {
          //获取当前文本真实的行数,如果是<br>符号getClientRects()方法也会变成一个区域
          var line = 0;
          var bottom = 0;
          for (var i = 0; i < arr.length; i++) {
            if (arr[i].bottom != bottom) {
              bottom = arr[i].bottom;
              line++;
            }
          }
          return line;
        }
      };
    })(jQuery);
    

    隐藏效果:


    隐藏.png

    展开效果


    展开.png

    注意

    getClientRects()的方式仅仅支持行内元素(inline),块级元素或者行内块级元素都只是识别为一个矩形区域,需要使用先把对应的标签转化为行内元素(inline)

    相关文章

      网友评论

          本文标题:基于getClientRects()实现行内元素多行文本展开收起

          本文链接:https://www.haomeiwen.com/subject/cpyxrltx.html