使用JavaScript实现文本收起展开(省略)功能 |
|
省略号,作为一种常见的文本处理方式,在很多情况下都十分常见 。特别是当我们需要在省略号后面添加额外文字时,这种需求更是不少见 。
然而,仅仅依赖 CSS 来实现兼容性、流畅的文本省略效果是不现实的 。就拿 Vant4 的 TextEllipsis 文本省略功能来说,我们可以从中学到不少 。 参考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行: 需要给予文本限高 : row = 4
const maxHeight = Math.ceil(
(Number(rows) + 0.5) * pxToNum(lineHeight) + "一些其他的容器高度:比如padding"
);
在这个计算中,0.5 是一个调整值,用于在计算最大高度时考虑到文本行数的不确定性 。这个调整值的目的是为了确保即使行数计算稍微超过了预期的行数,也能够提前截断文本,以防止文本超出容器的高度限制 。 得到了高度,如何切割文字 注意看: 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);
当递归结束时,函数会返回最终的截断位置,即最佳的截断位置 。 递归都有自己结束判断,这个递归的结束点就在 计算中间位置 检查容器元素的高度是否超过了指定的最大高度限制 。如果超过了,说明当前截断位置过早,需要继续向左边界靠近进行截断;否则,说明当前截断位置过晚,需要继续向右边界靠近进行截断 。 最终找到,合适的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;
};
解析: 实现效果
实例代码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文本展开收起的资料请关注其它相关文章! |