使用JSDOM安全截断文章HTML内容

在Web开发中,经常需要处理大量的HTML内容,尤其是在展示文章预览、动态加载内容或限制显示长度等场景中。直接截断HTML字符串可能会导致页面布局混乱、样式错误或标签不完整等问题。为了安全地截断HTML内容,我们可以利用jsdom库来解析HTML,并构建截断后的HTML字符串。

1、引入JSDOM库

首先,确保已经安装了jsdom库。如果尚未安装,可以使用npm(Node.js的包管理器)进行安装:

bash 复制代码
npm install jsdom

2、安全截断HTML内容的策略

安全截断HTML内容的关键在于确保截断后的HTML依然保持结构的完整性。以下是一个使用jsdom库来实现安全截断HTML内容的策略:

  1. 使用JSDOM解析HTML :创建一个JSDOM实例来解析HTML内容,并获取到解析后的DOM树。
  2. 遍历DOM树:从DOM树的根节点开始,逐个遍历子节点。
  3. 处理文本节点:当遇到文本节点时,检查其长度是否超过最大长度限制。如果超过,则截断文本并添加省略号;否则,直接添加文本内容。
  4. 处理元素节点:当遇到元素节点时,首先检查整个元素(包括其内容)的长度是否超过最大长度限制。如果未超过,则直接添加该元素的outerHTML;如果超过,则需要进一步处理。
  5. 处理元素节点的内部文本:对于超过长度限制的元素节点,需要遍历其内部的文本节点,并尝试截断文本。由于直接截断元素可能会导致未关闭的标签,因此我们只截断内部的文本内容,并保留元素的开放标签。
  6. 返回截断后的HTML:遍历完成后,返回截断后的HTML字符串。

3、具体实现方法

下面是使用上述策略实现安全截断HTML内容的示例代码:

javascript 复制代码
const { JSDOM } = require('jsdom');  
  
function truncateHtml(html, maxLength) {  
  // 创建一个包含传入HTML的完整文档  
  const dom = new JSDOM(`<!DOCTYPE html><html><head></head><body>${html}</body></html>`);  
  const { document } = dom.window;  
    
  let totalLength = 0;  
  let truncatedHtml = '';  
  let currentNode = document.body.firstChild;  
    
  // 遍历DOM树  
  while (currentNode) {  
    if (currentNode.nodeType === Node.TEXT_NODE) { // 文本节点  
      const textContent = currentNode.textContent;  
      const remainingLength = maxLength - totalLength;  
  
      if (textContent.length > remainingLength) {  
        // 截断文本并添加省略号  
        truncatedHtml += textContent.substring(0, remainingLength) + '...';  
        break;  
      } else {  
        truncatedHtml += textContent;  
        totalLength += textContent.length;  
      }  
    } else if (currentNode.nodeType === Node.ELEMENT_NODE) { // 元素节点  
      // 检查整个元素(包括内容)的长度  
      const elementHtml = currentNode.outerHTML;  
      if (totalLength + elementHtml.length <= maxLength) {  
        truncatedHtml += elementHtml;  
        totalLength += elementHtml.length;  
      } else {  
        // 如果超过长度限制,则截断元素内的文本节点  
        const clone = currentNode.cloneNode(false); // 不复制子节点  
        truncatedHtml += '<' + clone.nodeName + '>'; // 添加开放标签  
          
        // 遍历子节点并尝试截断文本  
        for (let child of currentNode.childNodes) {  
          if (child.nodeType === Node.TEXT_NODE) {  
            const textClone = child.cloneNode(true); // 复制文本节点  
            const textContent = textClone.textContent;  
            const textLength = textContent.length;  
            if (totalLength + textLength <= maxLength) {  
              truncatedHtml += textContent;  
              totalLength += textLength;  
            } else {  
              truncatedHtml += textContent.substring(0, maxLength - totalLength) + '...';  
              break;  
            }  
          }  
        }  
          
        // 跳出循环,因为已经处理了超过长度的元素  
        break;  
      }  
    }  
      
    currentNode = currentNode.nextSibling;  
  }  
    
  // 返回截断后的HTML  
  return truncatedHtml;  
}  
  
// 使用示例  
const pageContent = '<p>这是一篇<b>很长</b>的文章,包含<a href="#">多个</a>HTML<br>标签。</p>';  
const truncatedContent = truncateHtml(pageContent, 50);  
console.log
相关推荐
Moment1 分钟前
面试官:一个接口使用postman这些测试很快,但是页面加载很慢怎么回事 😤😤😤
前端·后端·面试
诗书画唱4 分钟前
【前端面试题】JavaScript 核心知识点解析(第二十二题到第六十一题)
开发语言·前端·javascript
excel11 分钟前
前端必备:从能力检测到 UA-CH,浏览器客户端检测的完整指南
前端
前端小巷子18 分钟前
Vue 3全面提速剖析
前端·vue.js·面试
悟空聊架构24 分钟前
我的网站被攻击了,被干掉了 120G 流量,还在持续攻击中...
java·前端·架构
CodeSheep26 分钟前
国内 IT 公司时薪排行榜。
前端·后端·程序员
尖椒土豆sss30 分钟前
踩坑vue项目中使用 iframe 嵌套子系统无法登录,不报错问题!
前端·vue.js
遗悲风30 分钟前
html二次作业
前端·html
江城开朗的豌豆34 分钟前
React输入框优化:如何精准获取用户输入完成后的最终值?
前端·javascript·全栈
CF14年老兵34 分钟前
从卡顿到飞驰:我是如何用WebAssembly引爆React性能的
前端·react.js·trae