需求:实现按指定词数拆分HTML文本的简洁JS阅读折叠函数
问题根源
原代码直接用split(/\s/)拆分整个HTML字符串,完全没区分文本和标签结构——比如<p>第一段落 内容</p>会被拆成<p>第一段落和内容</p>这种破片,重组后自然破坏标签结构,还可能因空格位置异常导致重复生成容器。
正确思路是只统计文本节点里的单词,不碰HTML标签,等累计到指定单词数后,再把前后内容分别包裹到目标div中。
改进后的简洁实现
(function($) { $.fn.splitWords = function(wordLimit) { return this.each(function() { const $container = $(this); let wordCount = 0; let splitTriggered = false; const $wrap1 = $('<div class="px-text-wrap-1"></div>'); const $wrap2 = $('<div class="px-text-wrap-2"></div>'); // 遍历DOM节点,精准统计并拆分文本 function walkNode(node) { if (node.nodeType === Node.TEXT_NODE) { const text = node.textContent.trim(); if (!text) return; const words = text.split(/\s+/); if (!splitTriggered) { if (wordCount + words.length <= wordLimit) { wordCount += words.length; $wrap1.append(node.cloneNode(true)); } else { // 拆分当前文本节点,分配到两个容器 const remaining = wordLimit - wordCount; $wrap1.append(document.createTextNode(words.slice(0, remaining).join(' ') + ' ')); $wrap2.append(document.createTextNode(words.slice(remaining).join(' ') + ' ')); splitTriggered = true; } } else { $wrap2.append(node.cloneNode(true)); } } else if (node.nodeType === Node.ELEMENT_NODE) { const $clone = $(node).clone().empty(); if (!splitTriggered) { walkNode(node); splitTriggered ? $wrap2.prepend($clone) : $wrap1.append($clone); } else { $wrap2.append($clone); walkNode(node); } } } // 开始处理原容器的所有节点 walkNode(this); // 替换原内容 $container.empty().append($wrap1).append($wrap2); }); }; }(jQuery));
核心优化点
- 只操作文本节点:遍历DOM树,严格区分文本和元素标签,不会破坏原HTML结构
- 精准单词统计:仅统计可见文本的单词数,标签属性里的文本不会被误算
- 保留完整标签:拆分后原有的
<p>、<span>等标签会完整保留在对应容器中 - 避免重复容器:仅生成两个目标div,解决重复添加
px-text-wrap-2的问题
使用方法
和原代码完全一致:
$('.my-text').splitWords(40);
内容的提问来源于stack exchange,提问作者Bob
相关产品推荐
相关产品推荐

