0

0

如何正确使用 innerHTML 动态更新 DOM 元素内容而不嵌套重复标签

花韻仙語

花韻仙語

发布时间:2026-03-17 12:35:01

|

734人浏览过

|

来源于php中文网

原创

如何正确使用 innerHTML 动态更新 DOM 元素内容而不嵌套重复标签

本文详解在使用 innerHTML 动态更新列表项时,因误将完整 <li> 标签插入已有 <li> 内部导致结构错乱的问题,并提供安全、语义清晰的替换方案。

本文详解在使用 innerhtml 动态更新列表项时,因误将完整 `

  • ` 标签插入已有 `
  • ` 内部导致结构错乱的问题,并提供安全、语义清晰的替换方案。

    在前端开发中,动态更新 DOM 是常见需求,但若对 innerHTML 的作用范围理解偏差,极易引发 DOM 结构污染。典型问题如:调用 _renderWorkoutUpdated() 更新某条运动记录时,页面上出现“容器内嵌容器”的异常布局(即新 <li> 被写入旧 <li> 的内部),破坏原有语义结构与 CSS 样式继承。

    根本原因在于:原始代码中构建的 html 字符串完整包含 <li> 开闭标签,而目标节点 document.querySelector('.workout[data-id="..."]') 本身已是 <li> 元素。此时执行 .innerHTML = html,等效于将新的 <li> 作为子元素插入原 <li>,造成非法嵌套(<li><li>...</li></li>),浏览器虽会尝试容错渲染,但会导致样式错位、事件委托失效、无障碍访问异常等隐患。

    ✅ 正确做法是:只用 innerHTML 替换目标元素的 内容(content),而非覆盖其自身标签结构。即 HTML 字符串应仅包含 <li> 的子内容(如 .container、.workout__details 等),再单独更新目标 <li> 的属性(如 className、dataset 等)。

    以下是优化后的实现:

    Spell.tools
    Spell.tools

    高颜值AI内容营销创作工具

    下载

    立即学习前端免费学习笔记(深入)”;

    _renderWorkoutUpdated(currentWorkout) {
      // 构建内容片段:不含 <li> 标签,仅其内部结构
      let html = `
        <div class="container">
          <div class="workout__title">${currentWorkout.description}</div>
          <div class="dropdown">
            <div class="kebab-menu">
              <div class="bar"></div>
              <div class="bar"></div>
              <div class="bar"></div>
            </div>
            <div class="dropdown-content" id="dropdownContent">
              <div class="option">Edit</div>
              <div class="option">Delete</div>
              <div class="option">Delete All</div>
            </div>
          </div>
        </div>
    
        <div class="workout__details">
          <span class="workout__icon">${currentWorkout.type === 'running' ? '?' : '?'}</span>
          <span class="workout__value">${currentWorkout.distance}</span>
          <span class="workout__unit">km</span>
        </div>
        <div class="workout__details">
          <span class="workout__icon">⏱</span>
          <span class="workout__value">${currentWorkout.duration}</span>
          <span class="workout__unit">min</span>
        </div>
      `;
    
      // 按类型追加特有字段(注意:此处结尾不加 </li>)
      if (currentWorkout.type === 'running') {
        html += `
          <div class="workout__details">
            <span class="workout__icon">⚡️</span>
            <span class="workout__value">${currentWorkout.pace.toFixed(1)}</span>
            <span class="workout__unit">min/km</span>
          </div>
          <div class="workout__details">
            <span class="workout__icon">?</span>
            <span class="workout__value">${currentWorkout.cadence}</span>
            <span class="workout__unit">spm</span>
          </div>
        `;
      }
    
      if (currentWorkout.type === 'cycling') {
        html += `
          <div class="workout__details">
            <span class="workout__icon">⚡️</span>
            <span class="workout__value">${currentWorkout.speed.toFixed(1)}</span>
            <span class="workout__unit">km/h</span>
          </div>
          <div class="workout__details">
            <span class="workout__icon">⛰</span>
            <span class="workout__value">${currentWorkout.elevationGain}</span>
            <span class="workout__unit">m</span>
          </div>
        `;
      }
    
      // 定位目标 <li> 元素
      const targetLi = document.querySelector(`.workout[data-id="${currentWorkout.id}"]`);
      if (!targetLi) {
        console.warn(`No workout element found for ID: ${currentWorkout.id}`);
        return;
      }
    
      // ✅ 安全更新:仅替换内容,保留外层 <li> 结构
      targetLi.innerHTML = html;
      // ✅ 单独更新类名(避免 classList 被完全覆盖)
      targetLi.className = `workout workout--${currentWorkout.type}`;
    }

    ⚠️ 关键注意事项

    • 禁止在 innerHTML 中重复包裹父级标签:确保字符串仅含目标元素的子内容;
    • 属性需显式更新:如 className、dataset、id 等不能通过 innerHTML 修改,必须单独赋值;
    • 添加存在性校验:querySelector 可能返回 null,务必检查后再操作 DOM;
    • 考虑 XSS 风险:若 currentWorkout.description 等字段来自用户输入,应先做 HTML 转义(推荐使用 textContent 替代插值,或引入 DOMPurify 库);
    • 性能提示:高频更新时,可结合 DocumentFragment 或虚拟 DOM 方案进一步优化。

    该方案保持了 HTML 语义完整性,兼容 CSS 选择器(如 .workout--running .workout__details),并为后续事件委托(如监听 .option 点击)提供稳定结构基础。

  • HTML速学教程(入门课程)
    HTML速学教程(入门课程)

    HTML怎么学习?HTML怎么入门?HTML在哪学?HTML怎么学才快?不用担心,这里为大家提供了HTML速学教程(入门课程),有需要的小伙伴保存下载就能学习啦!

    下载

    本站声明:本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn

    热门AI工具

    更多
    DeepSeek
    DeepSeek

    幻方量化公司旗下的开源大模型平台

    豆包大模型
    豆包大模型

    字节跳动自主研发的一系列大型语言模型

    WorkBuddy
    WorkBuddy

    腾讯云推出的AI原生桌面智能体工作台

    腾讯元宝
    腾讯元宝

    腾讯混元平台推出的AI助手

    文心一言
    文心一言

    文心一言是百度开发的AI聊天机器人,通过对话可以生成各种形式的内容。

    讯飞写作
    讯飞写作

    基于讯飞星火大模型的AI写作工具,可以快速生成新闻稿件、品宣文案、工作总结、心得体会等各种文文稿

    即梦AI
    即梦AI

    一站式AI创作平台,免费AI图片和视频生成。

    ChatGPT
    ChatGPT

    最最强大的AI聊天机器人程序,ChatGPT不单是聊天机器人,还能进行撰写邮件、视频脚本、文案、翻译、代码等任务。

    相关专题

    更多
    c语言中null和NULL的区别
    c语言中null和NULL的区别

    c语言中null和NULL的区别是:null是C语言中的一个宏定义,通常用来表示一个空指针,可以用于初始化指针变量,或者在条件语句中判断指针是否为空;NULL是C语言中的一个预定义常量,通常用来表示一个空值,用于表示一个空的指针、空的指针数组或者空的结构体指针。

    255

    2023.09.22

    java中null的用法
    java中null的用法

    在Java中,null表示一个引用类型的变量不指向任何对象。可以将null赋值给任何引用类型的变量,包括类、接口、数组、字符串等。想了解更多null的相关内容,可以阅读本专题下面的文章。

    1153

    2024.03.01

    js 字符串转数组
    js 字符串转数组

    js字符串转数组的方法:1、使用“split()”方法;2、使用“Array.from()”方法;3、使用for循环遍历;4、使用“Array.split()”方法。本专题为大家提供js字符串转数组的相关的文章、下载、课程内容,供大家免费下载体验。

    761

    2023.08.03

    js截取字符串的方法
    js截取字符串的方法

    js截取字符串的方法有substring()方法、substr()方法、slice()方法、split()方法和slice()方法。本专题为大家提供字符串相关的文章、下载、课程内容,供大家免费下载体验。

    221

    2023.09.04

    java基础知识汇总
    java基础知识汇总

    java基础知识有Java的历史和特点、Java的开发环境、Java的基本数据类型、变量和常量、运算符和表达式、控制语句、数组和字符串等等知识点。想要知道更多关于java基础知识的朋友,请阅读本专题下面的的有关文章,欢迎大家来php中文网学习。

    1570

    2023.10.24

    字符串介绍
    字符串介绍

    字符串是一种数据类型,它可以是任何文本,包括字母、数字、符号等。字符串可以由不同的字符组成,例如空格、标点符号、数字等。在编程中,字符串通常用引号括起来,如单引号、双引号或反引号。想了解更多字符串的相关内容,可以阅读本专题下面的文章。

    651

    2023.11.24

    java读取文件转成字符串的方法
    java读取文件转成字符串的方法

    Java8引入了新的文件I/O API,使用java.nio.file.Files类读取文件内容更加方便。对于较旧版本的Java,可以使用java.io.FileReader和java.io.BufferedReader来读取文件。在这些方法中,你需要将文件路径替换为你的实际文件路径,并且可能需要处理可能的IOException异常。想了解更多java的相关内容,可以阅读本专题下面的文章。

    1269

    2024.03.22

    php中定义字符串的方式
    php中定义字符串的方式

    php中定义字符串的方式:单引号;双引号;heredoc语法等等。想了解更多字符串的相关内容,可以阅读本专题下面的文章。

    1206

    2024.04.29

    抖漫入口地址合集
    抖漫入口地址合集

    本专题整合了抖漫入口地址相关合集,阅读专题下面的文章了解更多详细地址。

    1

    2026.03.17

    热门下载

    更多
    网站特效
    /
    网站源码
    /
    网站素材
    /
    前端模板

    精品课程

    更多
    相关推荐
    /
    热门推荐
    /
    最新课程
    关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
    php中文网:公益在线php培训,帮助PHP学习者快速成长!
    关注服务号 技术交流群
    PHP中文网订阅号
    每天精选资源文章推送

    Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号