当前位置: 代码网 > it编程>编程语言>Javascript > 使用JavaScript实现文本收起展开(省略)功能

使用JavaScript实现文本收起展开(省略)功能

2024年05月15日 Javascript 我要评论
省略号,作为一种常见的文本处理方式,在很多情况下都十分常见。特别是当我们需要在省略号后面添加额外文字时,这种需求更是不少见。然而,仅仅依赖 css 来实现兼容性、流畅的文本省略效果是不现实的。就拿 v

省略号,作为一种常见的文本处理方式,在很多情况下都十分常见。特别是当我们需要在省略号后面添加额外文字时,这种需求更是不少见。

然而,仅仅依赖 css 来实现兼容性、流畅的文本省略效果是不现实的。就拿 vant4textellipsis 文本省略功能来说,我们可以从中学到不少。

参考vant4:textellipsis 文本省略,为大家分析一波案例(感觉麻烦可以去看下面的附带代码)。

在整个代码中,关键之处在于使用了 tail、middletail 等关键手段。我们着重讨论 tail,即在文本尾部插入内容的操作。

简单的css隐藏

大家或多或少都曾编写过 css 省略文本的代码。比如,要将文本限制在四行内显示,可以使用以下 css 代码:

隐藏为四行

overflow: hidden;
display: -webkit-box;
-webkit-box-orient: vertical;
-webkit-line-clamp: 4; /* 控制显示行数 */

其中的限制

尽管如此,这种方法有着一定的局限性:

  • 如何在省略号后添加展开、收起等文字?
  • 添加后,如何保证文字与省略号在同一行?
  • 展开后,如何保证文字在合适位置显示?

纯 css 可以实现这些效果,但实际操作起来会比较困难。

既然 css 不够理想,我们可以考虑使用 javascript 来实现这些功能。

首先,让我们来分析一波:

  • 收起时保留的高度是多少?
  • 如何截取超出高度的文字内容?
  • 如何确保截取后的文字内容不影响原来的渲染和展示?

完成以上三点,我们就完成了任务。

开始分析

<div class="root">
    散文是一种文学形式,与之相对的称为韵文或诗文。散文可分为广义与狭义的解释,其中,广义散文最容易辨识与定义的方式,是“松散”的结构。也就是说,扣除其它文学形式重叠部分,运用普通语法结构,不讲究音韵,不讲究排比,没有任何束缚及限制的文字梳理方式,都可称为散文。除此,狭义散文是单指文学范畴内,结构松散之非韵文作品。文学专指的散文,历代作品有着各时代不同流变的脉络,而正因为松散带来的自由,散文作品表达出的思想通常有着丰富与圆满的特色
</div>
<style>
  .root {
    line-height: 1.6;
    overflow-wrap: break-word;
    word-break: break-all;
  }
</style>

首先解决:收起时要保留的高度是多少?

假设我们保留4行:

需要给予文本限高 : line-height: 1.6;

row = 4
const maxheight = math.ceil(
    (number(rows) + 0.5) * pxtonum(lineheight) + "一些其他的容器高度:比如padding"
);

在这个计算中,0.5 是一个调整值,用于在计算最大高度时考虑到文本行数的不确定性。这个调整值的目的是为了确保即使行数计算稍微超过了预期的行数,也能够提前截断文本,以防止文本超出容器的高度限制。

得到了高度,如何切割文字

注意看:tail() 函数是一个递归函数,用于在给定的容器高度限制下,计算文本的截断位置。让我来详细解释一下 tail() 函数的工作原理:

const tail = (left, right) => {

    if (right - left <= 1) {
      return content.slice(0, left) + dots;
    }
    
    const middle = math.round((left + right) / 2);
    container.innertext = content.slice(0, middle) + dots + actiontext;
    
    if (container.offsetheight > maxheight) {
      return tail(left, middle);
    }
    return tail(middle, right);
  };

  container.innertext = tail(0, end);

当递归结束时,函数会返回最终的截断位置,即最佳的截断位置。

递归都有自己结束判断,这个递归的结束点就在right - left <= 1,

计算中间位置 middle ,并将文本内容从左边界到中间位置加上省略符号,然后设置到容器元素中

检查容器元素的高度是否超过了指定的最大高度限制。如果超过了,说明当前截断位置过早,需要继续向左边界靠近进行截断;否则,说明当前截断位置过晚,需要继续向右边界靠近进行截断。

最终找到,合适的middle值,在一起返回 content.slice(0, left) + dots 作为结点的 innertext 文字。

期间,一直在收缩,就算高度相同也在收缩右边界的内容, right - left <= 1 的作用就是刚刚好实现的截断位置以满足给定的最大高度限制,不会超出限制。

总结:这个 tail() 函数使用递归的方式,根据给定的容器高度限制,计算出文本的截断位置。递归的结束判断在 right - left <= 1,通过不断调整 middle 的值,最终找到合适的截断位置以满足给定的最大高度限制,不会超出限制。

在切割下,保证文字内容不影响原来的渲染展示

为了不影响原文本的渲染展示,我们使用了克隆节点的方式。这里参考了 vant 中的代码,并做了适当修改。

修改成了,更加适合js宝宝体质的代码

const rootnode = document.queryselector(".root");

const clonecontainer = () => {
  // clonecontainer就是为了得到文本的高度
  if (!rootnode || !rootnode.isconnected) return;

  const originstyle = window.getcomputedstyle(rootnode);
  const container = document.createelement('div');
  const stylenames= array.prototype.slice.apply(originstyle);

  stylenames.foreach((name) => {
    container.style.setproperty(name, originstyle.getpropertyvalue(name));
  });

  container.style.position = 'fixed'; // 不在文档流中
  container.style.zindex = '-9999'; // 看不到
  container.style.top = '-9999px'; // 看不到
  container.style.height = 'auto';
  container.style.minheight = 'auto';
  container.style.maxheight = 'auto';

  container.innertext = content;
  document.body.appendchild(container);

  return container;
};

解析:window.getcomputedstyle 是一个用于获取指定元素的所有计算样式的方法。它返回一个 cssstyledeclaration 对象,其中包含了指定元素的所有计算样式属性及其对应的值。

实现效果

实例代码

html

<style>
  .root {
    padding: 12px;
    line-height: 1.6;
    overflow-wrap: break-word;
    word-break: break-all;
  }
</style>

<body>
  <div class="root">
    散文是一种文学形式,与之相对的称为韵文或诗文。散文可分为广义与狭义的解释,其中,广义散文最容易辨识与定义的方式,是“松散”的结构。也就是说,扣除其它文学形式重叠部分,运用普通语法结构,不讲究音韵,不讲究排比,没有任何束缚及限制的文字梳理方式,都可称为散文。除此,狭义散文是单指文学范畴内,结构松散之非韵文作品。文学专指的散文,历代作品有着各时代不同流变的脉络,而正因为松散带来的自由,散文作品表达出的思想通常有着丰富与圆满的特色
  </div>
</body>
<script src="textellipsis.js"> </script>

js代码

document.addeventlistener("domcontentloaded", function() {
  
let expanded =true;
let collapsetext = "收起";
let expandtext = "展开";
const rows = 3;
let actiontext = expanded ? collapsetext : expandtext;
let hasaction = false;
const rootnode = document.queryselector(".root");
const content = rootnode.innertext;
let text = "";
const dots = "...";

const pxtonum = (value) => {
  if (!value) return 0;
  const match = value.match(/^\d*(\.\d*)?/);
  return match ? number(match[0]) : 0;
};

const clonecontainer = () => {
  // clonecontainer就是为了得到文本的高度
  if (!rootnode || !rootnode.isconnected) return;

  const originstyle = window.getcomputedstyle(rootnode);
  const container = document.createelement('div');
  const stylenames= array.prototype.slice.apply(originstyle);

  stylenames.foreach((name) => {
    container.style.setproperty(name, originstyle.getpropertyvalue(name));
  });

  container.style.position = 'fixed';
  container.style.zindex = '-9999';
  container.style.top = '-9999px';
  container.style.height = 'auto';
  container.style.minheight = 'auto';
  container.style.maxheight = 'auto';

  container.innertext = content;
  document.body.appendchild(container);

  return container;
};

const calcellipsised = () => {
  const calcellipsistext = (
    container,
    maxheight
  ) => {
    const end = content.length;

    const calcellipse = () => {
      const tail = (left, right) => {

        if (right - left <= 1) {
          return content.slice(0, left) + dots;
        }

        const middle = math.round((left + right) / 2);

        container.innertext = content.slice(0, middle) + dots + actiontext;

        if (container.offsetheight > maxheight) {
          return tail(left, middle);
        }

        return tail(middle, right);
      };

      container.innertext = tail(0, end);
    };

    calcellipse();

    return container.innertext;
  };

  const container = clonecontainer();

  if (!container) {
    needrecalculate = true;
    return;
  }

  let { paddingbottom, paddingtop, lineheight } = container.style;

  const maxheight = math.ceil(
    (number(rows) + 0.5) * pxtonum(lineheight) +
      pxtonum(paddingtop) +
      pxtonum(paddingbottom),
  );

  if (maxheight < container.offsetheight) {
    hasaction = true;
    text = calcellipsistext(container, maxheight);
  } else {
    hasaction = false;
    text = content;
  }

  document.body.removechild(container);
};

const toggle = (isexpanded = !expanded) => {
  expanded = isexpanded;
  actiontext = expanded ? collapsetext : expandtext;
};


const renderaction = () => {
  calcellipsised();
  const container = document.createelement('span');
  container.classlist.add("expend_txt");
  container.addeventlistener('click',()=>{
    toggle();
    container.innertext = hasaction ? actiontext : null;
    rootnode.innertext = expanded ? content : text;
    rootnode.appendchild(container);
  });
  container.innertext = hasaction ? actiontext : null;;
  rootnode.appendchild(container);
}

renderaction()

})

以上就是使用javascript实现文本收起展开(省略)功能的详细内容,更多关于javascript文本展开收起的资料请关注代码网其它相关文章!

(0)

相关文章:

版权声明:本文内容由互联网用户贡献,该文观点仅代表作者本人。本站仅提供信息存储服务,不拥有所有权,不承担相关法律责任。 如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 2386932994@qq.com 举报,一经查实将立刻删除。

发表评论

验证码:
Copyright © 2017-2025  代码网 保留所有权利. 粤ICP备2024248653号
站长QQ:2386932994 | 联系邮箱:2386932994@qq.com