JS实现多行文本的展开/收起

7,044 阅读3分钟

问题:

在一些多行文本展示的页面中,出于视觉、交互的友好性,时常会在展示多行文本内容时,要求内容超出三(概数)行时,剩下的内容被隐藏,并以 ...展开 收尾;

spread

点击 展开 显示所有文本内容,内容的尾部会有一个 收起。如此可反复操作。

collapse

解析:

这个问题如果草率一点,直接使用css进行多行文本超出...,

overflow: hidden;
text-overflow: ellipsis;
display: -webkit-box;
-webkit-line-clamp: 2;
-webkit-box-orient: vertical;

换行添加"展开"按钮即可。可是呢,这个玩意好用是好用,看到-webkit-的前缀,我们就能敏感的知道存在浏览器兼容性问题。严格说来,这种换行显示 “展开”按钮的形式与我们想要的还是有点区别。

如何达成我们的目的,这里我们就不得不说一下 element.getClientRects() 这个方法,该方法返回一个指向客户端中每一个盒子的边界矩形的矩形集合。 其中对于块元素, getClientRects 方法只会返回一个矩形,对于行内元素来说,元素内部的每一行都会有一个边框,即返回多行边框的一个集合。这后半句我们可以细细品品!!!此外在浏览器兼容一栏我们会看到,简直完美!!!

兼容性

解决思路

问题解决的关键是用行内元素span将要处理的多行文本包裹起来,再通过 element.getClientRects 方法获取所有DOM行数列表DOMRectList,其中包含每行DOM边框 DOMRect 。我们每次将文本内容每次去掉一个字符并与“...展开”拼接起来,然后计算出行数,如此反复,当行数等于我们预设的行数 n 时即可。当循环结束后,我们就可以获取到指定的那段与“...展开”恰好实现 n 显示的内容。获取到截断的那段文本与原先完整的内容,我们就可以愉快的进行“展开”、“收起”的操作了。

  1. 准备一段html片段

    <!-- css 样式 -->
    <style>
    .text {
        margin: 0 auto;
        width: 200px;
        background: #ffffff;
        color: #606266;
        word-break: break-word;
        padding: 10px 15px;
        border:1px solid #dfdfdf;
        border-radius: 4px;
    }
    .collapse-text {
        color: #409eff;
        cursor: pointer;
    }
    .collapse-text:active {
        color: #3a8ee6;
    }
    </style>
    <!-- html 片段 -->
        <div class="text">
            <span class="span">近日,陕西省考古研究院考古人员发掘了一处唐代贵族家族墓地,在一座夫妻合葬中发现一方由唐代大书法家颜真卿书写的墓志铭。考古人员说,颜真卿书写墓志的年代是天宝五年,它是在颜真卿三十八岁的时候书写的,这是目前唯一经过科学考古发掘出土的颜真卿早期书法真迹。</span>
        </div>
    
  2. 定义变量存储源文本数据,以及定义需要用来计算的文本变量

    // 计算文本行数
    function getLength(rects){
        var line = 0, lastBottom=0;
        for(var i=0,len=rects.length;i<len;i++){
            if(rects[i].bottom == lastBottom){
                continue
            }
            lastBottom = rects[i].bottom;
            line++;
        }
        return line;
    }
    // 初始化变量定义、赋值
    var span1 = document.getElementsByClassName('span')[0];
    var originalText = span1.innerHTML; // 源数据存储变量
    var changeText = span1.innerHTML;	// 计算数据变量
    var span1Rects = span1.getClientRects();
    var h = getLength(span1Rects); //行数
    
  3. 循环删除文本内容的最后一个字符,并与预设的行数比对,获取到目标字符串

    // 预设函数:3
    while(h>3) { 
        var step = 1;
        changeText = changeText.slice(0,-step);
        span1.innerHTML = changeText + '<span>...</span><span id="collapse-btn" class="collapse-text" data-spread="false"> 展开</span>';
        h = getLength(span1.getClientRects());
    }
    
  4. 为展开/收起按钮添加事件

    window.addEventListener('click',function(e){
        var state = document.getElementById('collapse-btn').dataset.spread;
        if(state === 'false'){
            span1.innerHTML = originalText + '<span id="collapse-btn" class="collapse-text" data-spread="true">收起</span>'
            }else{
            span1.innerHTML = changeText + '<span>...</span><span id="collapse-btn" class="collapse-text" data-spread="false"> 展开</span>'
        }
    });
    

至此,我们实现了“展开”、"收起"效果,如文章开始给出的效果图。