‘展开收起’ CSS & JS方案

·  阅读 672
‘展开收起’ CSS & JS方案
常规业务需求中大前端的工作者应该都遇到过类似需求,固定展示 N 行,句末显示 展开 ,点击展示 全部 ,可进行 收起 操作。

目标

image.png

方案

纯CSS方案

  • 1.先实现第一步达到行数要求时显示....,这个不多赘述

<div class="desc">
    沉默的你,阳光萧瑟的树林,那些你爱的人,温柔的那么柔软,无知的我
    是落叶落寞又落魄,看我残留的热情,穿插沉默的现在,呼啸而过的青春,沉默不语的你,即使给我个灿烂明天
</div>
复制代码
   .desc {
    display: -webkit-box;
    -webkit-line-clamp: 3; // 文本展示最大的行数
    -webkit-box-orient: vertical;
    overflow: hidden;
    text-align: justify;
    font-size: 16px;
    line-height: 44px;
  }
复制代码

image.png

  • 2.显示展开/收起按钮
<div class="desc">
    <button class="btn">展开</button>
    沉默的你,阳光萧瑟的树林,那些你爱的人,温柔的那么柔软,无知的我
    是落叶落寞又落魄,看我残留的热情,穿插沉默的现在,呼啸而过的青春,沉默不语的你,即使给我个灿烂明天
</div>
复制代码
.btn {
    float: right;
    clear: both;
    background-color: #f00;
    border: none;
    color: #fff;
    line-height: 24px;
}
.desc {
    display: -webkit-box;
    -webkit-line-clamp: 3;
    -webkit-box-orient: vertical;
    overflow: hidden;
    text-align: justify;
    font-size: 16px;
    line-height: 44px;
}
复制代码

利用float 浮动,让按钮进入文本环绕式布局,但此时我们可以看到,按钮显示的位置为右上角,与需求有出入,如何让他下来呢,可利用的样式 padding margin,布局边界,优先采用margin,看下效果

image.png

按钮移动到右下角,但文本的环绕模式并没有保留,文字渲染区域被切割。margin无法满足,因为文档中上方的空间依然被按钮所占据,而按钮元素并没有脱离文档流,自然文字无法进行空白区域的二次渲染。

  • 3.保留浮动布局,让按钮移动下来,增加一个元素把按钮挤下来
    .btn {
     float: right;
     clear: both; // 清除浮动
     background-color: #f00;
     border: none;
     color: #fff;
     line-height: 24px;
    }
    .desc {
     display: -webkit-box;
     -webkit-line-clamp: 3;
     -webkit-box-orient: vertical;
     overflow: hidden;
     text-align: justify;
     font-size: 16px;
     position: relative;
     line-height: 44px;
    }
    .desc::before{
     content: '';
     float: right;
     width: 10px;
     height: 46px;
     background: #000;
     overflow: hidden;
    }
    复制代码

image.png

  • 4.隐藏模式利用伪类,达成UI还原度
    .desc::before{
        content: '';
        float: right;
        width: 0px;
        height: 46px;
        overflow: hidden;
    }
    复制代码

image.png

  • 5.当文本行数不出现溢出是,按钮无法自动隐藏 看效果

image.png

解决方案:类上,采用伪类遮盖的方式障眼法

.desc::after {
    content: '';
    position: absolute;
    width: 100%;
    height: 100%;
    background: #000;
}
复制代码

绝对定位,不设置 left top bottom right; left top 会默认进入文档流 image.png

优化:伪类背景色与大背景颜色一致,即可解决问题了

image.png

  • 6.检查配置,提高复用性
    // desc::before 的高度严格依赖了字体行高,这相当于写死的配置,复用性太差。
    // height 相当于元素100% - 按钮的高度 - (行高-按钮高)/2
    // 自然想到一个属性 calc(100%- 34px)
    
    // 会发现height :100% 在标准文档流里面是获取不到的。 可通过flex 布局打破
    
    修改元素节点,增加负类元素
    
    <div class="content">
        <div class="desc">
            <button class="btn">展开</button>
            沉默的你,阳光萧瑟的树林,那些你爱的人,温柔的那么柔软,无知的我,是落叶落寞又落魄,看我残留的热情
            穿插沉默的现在,呼啸而过的青春,沉默不语的你,即使给我个灿烂明天
        </div>
      </div>
    
     .content{
        display: flex;
        overflow: hidden;
      }
    
    这时候就可以正确获取元素height,因为calc 存在兼容性,更好的方案应该是
    height: 100% margin-bottom:-34px
    性能也更加友好
复制代码
  • 7.完整实现代码
.content{
    display: flex;
    overflow: hidden;
  }
  .btn {
    float: right;
    clear: both;
    background-color: #f00;
    border: none;
    color: #fff;
    line-height: 24px;
  }
  .desc {
    display: -webkit-box;
    -webkit-line-clamp: 3;
    -webkit-box-orient: vertical;
    overflow: hidden;
    text-align: justify;
    font-size: 16px;
    position: relative;
    line-height: 44px;
    word-break: break-all;
  }
  .desc::before{
    content: '';
    float: right;
    width: 0px;
    /* height: calc(100% - 32px); */
    background: #000;
    overflow: hidden;
    height: 100%;
    margin-bottom: -34px;
    /* 性能更好,兼容性更好  (line-height - btn height)/2 + btn height */
  }

  .desc::after {
    content: '';
    position: absolute;
    width: 100%;
    height: 100px;
    background: #fff;
  }
复制代码
<div class="content">
    <div class="desc">
    <button class="btn">展开</button>
    沉默的你,阳光萧瑟的树林,那些你爱的人,温柔的那么柔软,无知的我,是落叶落寞又落魄,看我残留的热情
    穿插沉默的现在,呼啸而过的青春,沉默不语的你,即使给我个灿烂明天
    </div>
  </div>
复制代码
下沉为业务基础组件,完全的灵活性,分析以上代码中的样式表
文本行高,采用js 获取 document.defaultView.getComputedStyle(el)["line-height"]
按钮的行高直接继承

JS 实现方案

let el = this.$el;

  let lineHeight = parseFloat(
    document.defaultView
      .getComputedStyle(el)
      ["line-height"].replace("px", "")
  );

  let COMPAT_VALUE = 10; // 取 10 作为一个缓冲值,防止不同浏览器展示的高度不同

  if (el.offsetHeight > lineHeight * this.maxLine + COMPAT_VALUE) {
    // 超出最大行,需要折叠操作
    this.foldState = FOLDED;

    // 延迟一下让 展开的按钮可以更新到页面上
    this.$nextTick(_ => {
      while (el.offsetHeight > lineHeight * this.maxLine + COMPAT_VALUE) {
        // 为了处理 emoji 的删除, refer to http://www.alloyteam.com/2016/12/javascript-has-a-unicode-sinkhole/
        let tmpArray = Array.from(this.textEl.textContent);
        tmpArray.pop();
        this.textEl.textContent = tmpArray.join("");
        // console.log(this.textEl.textContent, el.offsetHeight)
      }
    });
  }
复制代码
实现思想: 把需要展示的按钮 省略号全部丢到 父类dom 元素中,通过循环计算 实际渲染的高度与 可展示的最大高度比较,对文本内容进行减法运算。实现最终高度一致

####### 参考:

juejin.cn/post/696390…

juejin.cn/post/684490…

分类:
前端
标签: