pin_drop当前位置:知识文库 ❯ 图文

JS集成:HTML DOM修改属性 - 详细教程与实战指南

教程简介

HTML元素的属性(Attribute)是元素的重要组成部分,它们提供了元素的附加信息,如ID、类名、链接地址、图片源等。DOM提供了多种方法来读取、设置和删除元素属性,同时HTML5引入的data-*自定义属性为存储额外数据提供了标准化的方式。理解属性(Attribute)与特性(Property)的区别,以及各种属性操作方法的使用场景,是前端开发的基本功。本教程将全面讲解DOM属性操作的各种方法、dataset属性、自定义属性data-*以及属性与特性的区别。


核心概念

属性(Attribute)与特性(Property)的区别

这是DOM中一个容易混淆的概念:

  • 属性(Attribute):HTML标签上的键值对,定义在HTML源代码中,类型始终是字符串

  • 特性(Property):DOM对象上的属性,是JavaScript对象的属性,类型可以是任意类型

代码示例

<!DOCTYPE html>
<html lang="zh-CN">
<head>
  <meta charset="UTF-8">
  <title>属性与特性的区别</title>
</head>
<body>
  <input id="myInput" type="text" value="Hello" class="form-input">

  <script>
    var input = document.getElementById('myInput');

    // Attribute(属性):HTML标签上的,始终是字符串
    console.log(input.getAttribute('value'));   // "Hello"(字符串)
    console.log(input.getAttribute('class'));   // "form-input"(字符串)
    console.log(input.getAttribute('id'));      // "myInput"(字符串)

    // Property(特性):DOM对象的属性,类型多样
    console.log(input.value);    // "Hello"(字符串)
    console.log(input.className); // "form-input"(字符串)
    console.log(input.id);       // "myInput"(字符串)
    console.log(input.type);     // "text"(字符串)

    // 关键区别1:类型不同
    // <input type="checkbox" checked>
    var checkbox = document.createElement('input');
    checkbox.type = 'checkbox';
    checkbox.setAttribute('checked', '');  // Attribute: ""(字符串)
    checkbox.checked = true;               // Property: true(布尔值)

    // 关键区别2:值可能不同步
    input.value = 'New Value';
    console.log(input.getAttribute('value'));  // "Hello"(Attribute未变)
    console.log(input.value);                   // "New Value"(Property已变)

    // 关键区别3:setAttribute改变Attribute,Property可能跟随
    input.setAttribute('value', 'Another Value');
    console.log(input.getAttribute('value'));  // "Another Value"
    console.log(input.value);                   // 取决于用户是否修改过

    // 关键区别4:某些Property和Attribute名称不同
    // class Attribute -> className Property
    // for Attribute -> htmlFor Property
    // tabindex Attribute -> tabIndex Property
    // readonly Attribute -> readOnly Property
    // maxlength Attribute -> maxLength Property
  </script>
</body>
</html>

同步规则总结

情况 Attribute -> Property Property -> Attribute
标准属性(非表单value) 同步 同步
表单value 初始同步 不同步
自定义属性 不同步(除非用dataset) 不同步
data-*属性 通过dataset同步 通过dataset同步

语法与用法

1. getAttribute

getAttribute 方法获取元素指定属性的值。

代码示例

<!DOCTYPE html>
<html lang="zh-CN">
<head>
  <meta charset="UTF-8">
  <title>getAttribute示例</title>
</head>
<body>
  <a id="myLink" href="https://example.com" target="_blank" class="link primary" data-category="external">
    示例链接
  </a>

  <script>
    var link = document.getElementById('myLink');

    // 获取标准属性
    console.log(link.getAttribute('href'));     // "https://example.com"
    console.log(link.getAttribute('target'));   // "_blank"
    console.log(link.getAttribute('class'));    // "link primary"

    // 获取自定义属性
    console.log(link.getAttribute('data-category')); // "external"

    // 属性不存在时返回null
    console.log(link.getAttribute('title'));    // null

    // 布尔属性:存在时返回空字符串,不存在时返回null
    // <input disabled>
    // input.getAttribute('disabled') -> ""
    // input.getAttribute('nonexistent') -> null

    // 注意:getAttribute返回的始终是字符串
    // <input maxlength="10">
    // input.getAttribute('maxlength') -> "10"(字符串)
    // input.maxLength -> 10(数字)
  </script>
</body>
</html>

2. setAttribute

setAttribute 方法设置元素的属性值,如果属性不存在则创建。

代码示例

<!DOCTYPE html>
<html lang="zh-CN">
<head>
  <meta charset="UTF-8">
  <title>setAttribute示例</title>
</head>
<body>
  <div id="demo"></div>
  <input id="myInput" type="text">

  <script>
    var demo = document.getElementById('demo');
    var input = document.getElementById('myInput');

    // 设置标准属性
    demo.setAttribute('id', 'new-id');
    demo.setAttribute('class', 'container');
    demo.setAttribute('title', '提示文本');

    // 设置自定义属性
    demo.setAttribute('data-role', 'main');
    demo.setAttribute('data-index', '0');

    // 设置布尔属性
    input.setAttribute('disabled', '');  // 禁用输入框
    input.setAttribute('required', '');  // 必填

    // 注意:setAttribute的值始终被转为字符串
    demo.setAttribute('data-count', 42);
    console.log(demo.getAttribute('data-count')); // "42"(字符串)
    console.log(typeof demo.getAttribute('data-count')); // "string"

    // setAttribute vs Property
    demo.setAttribute('class', 'my-class');  // 设置Attribute
    demo.className = 'my-class';              // 设置Property(推荐)

    // 对于标准属性,推荐直接使用Property
    input.id = 'newInputId';       // 推荐
    input.type = 'password';       // 推荐
    input.placeholder = '请输入';  // 推荐
  </script>
</body>
</html>

3. removeAttribute

removeAttribute 方法移除元素的指定属性。

代码示例

<!DOCTYPE html>
<html lang="zh-CN">
<head>
  <meta charset="UTF-8">
  <title>removeAttribute示例</title>
</head>
<body>
  <input id="myInput" type="text" disabled required class="form-input" value="Hello">

  <script>
    var input = document.getElementById('myInput');

    // 移除布尔属性(启用输入框)
    input.removeAttribute('disabled');

    // 移除required
    input.removeAttribute('required');

    // 移除class
    input.removeAttribute('class');

    // 移除value
    input.removeAttribute('value');

    // 移除自定义属性
    input.removeAttribute('data-custom');

    // 注意:removeAttribute vs 将值设为空字符串
    input.setAttribute('disabled', '');  // 添加disabled属性
    input.removeAttribute('disabled');   // 移除disabled属性(正确)
    input.setAttribute('disabled', '');  // disabled="" 仍然禁用
    // 布尔属性的存在即为true,值无关紧要
  </script>
</body>
</html>

4. hasAttribute

hasAttribute 方法检测元素是否具有指定属性。

代码示例

<!DOCTYPE html>
<html lang="zh-CN">
<head>
  <meta charset="UTF-8">
  <title>hasAttribute示例</title>
</head>
<body>
  <input id="myInput" type="text" disabled data-role="search">

  <script>
    var input = document.getElementById('myInput');

    // 检测属性是否存在
    console.log(input.hasAttribute('disabled'));    // true
    console.log(input.hasAttribute('data-role'));   // true
    console.log(input.hasAttribute('type'));        // true
    console.log(input.hasAttribute('placeholder')); // false
    console.log(input.hasAttribute('class'));       // false

    // 实际应用:条件性操作
    if (input.hasAttribute('disabled')) {
      input.removeAttribute('disabled');
      console.log('输入框已启用');
    }

    // 检测布尔属性
    // <details open>
    // details.hasAttribute('open') -> true
  </script>
</body>
</html>

5. attributes属性

attributes 属性返回元素所有属性节点的NamedNodeMap集合。

代码示例

<!DOCTYPE html>
<html lang="zh-CN">
<head>
  <meta charset="UTF-8">
  <title>attributes属性示例</title>
</head>
<body>
  <div id="demo" class="container" data-role="main" title="示例" aria-label="主要内容">
    内容
  </div>

  <script>
    var demo = document.getElementById('demo');

    // 获取所有属性
    var attrs = demo.attributes;
    console.log('属性数量:', attrs.length); // 5

    // 遍历所有属性
    for (var i = 0; i < attrs.length; i++) {
      var attr = attrs[i];
      console.log(attr.name + ' = ' + attr.value);
    }
    // id = demo
    // class = container
    // data-role = main
    // title = 示例
    // aria-label = 主要内容

    // 通过索引访问
    console.log(attrs[0].name);  // "id"
    console.log(attrs[0].value); // "demo"

    // 通过名称访问
    console.log(attrs['class'].value);     // "container"
    console.log(attrs.getNamedItem('id')); // Attr节点 {name: "id", value: "demo"}

    // 修改属性
    var classAttr = attrs.getNamedItem('class');
    if (classAttr) {
      classAttr.value = 'new-class';
    }

    // 转换为普通对象
    var attrObj = {};
    for (var i = 0; i < attrs.length; i++) {
      attrObj[attrs[i].name] = attrs[i].value;
    }
    console.log(attrObj);
  </script>
</body>
</html>

6. dataset属性

dataset 属性提供对元素所有data-*自定义属性的读写访问,返回一个DOMStringMap对象。

代码示例

<!DOCTYPE html>
<html lang="zh-CN">
<head>
  <meta charset="UTF-8">
  <title>dataset属性示例</title>
</head>
<body>
  <div id="user-card"
       data-user-id="12345"
       data-user-name="张三"
       data-user-role="admin"
       data-is-active="true"
       data-login-count="42"
       data-bg-color="#ff6600">
    用户卡片
  </div>

  <script>
    var card = document.getElementById('user-card');

    // 读取data-*属性
    console.log(card.dataset.userId);      // "12345"
    console.log(card.dataset.userName);    // "张三"
    console.log(card.dataset.userRole);    // "admin"
    console.log(card.dataset.isActive);    // "true"
    console.log(card.dataset.loginCount);  // "42"
    console.log(card.dataset.bgColor);     // "#ff6600"

    // 命名规则:data-* 属性名转换为驼峰
    // data-user-id -> dataset.userId
    // data-user-name -> dataset.userName
    // data-bg-color -> dataset.bgColor
    // data-my-long-attr -> dataset.myLongAttr

    // 设置data-*属性
    card.dataset.userRole = 'moderator';
    card.dataset.lastLogin = '2024-01-15';

    // 删除data-*属性
    delete card.dataset.bgColor;

    // 遍历所有data-*属性
    Object.keys(card.dataset).forEach(function(key) {
      console.log('data-' + key + ' = ' + card.dataset[key]);
    });

    // 注意:dataset的值始终是字符串
    console.log(typeof card.dataset.isActive);    // "string"(不是boolean)
    console.log(typeof card.dataset.loginCount);  // "string"(不是number)

    // 需要手动转换类型
    var isActive = card.dataset.isActive === 'true';
    var loginCount = parseInt(card.dataset.loginCount, 10);
  </script>
</body>
</html>

7. 自定义属性data-*详解

代码示例

<!DOCTYPE html>
<html lang="zh-CN">
<head>
  <meta charset="UTF-8">
  <title>自定义属性data-*详解</title>
  <style>
    .tooltip { position: relative; cursor: help; border-bottom: 1px dashed; }
    .tooltip::after {
      content: attr(data-tooltip);
      position: absolute; bottom: 100%; left: 50%;
      transform: translateX(-50%);
      background: #333; color: white; padding: 4px 8px;
      border-radius: 4px; font-size: 12px; white-space: nowrap;
      opacity: 0; transition: opacity 0.2s; pointer-events: none;
    }
    .tooltip:hover::after { opacity: 1; }
  </style>
</head>
<body>
  <h1>自定义属性data-*详解</h1>

  <!-- CSS中使用data-*属性 -->
  <p>将鼠标悬停在<span class="tooltip" data-tooltip="这是提示文本">提示文字</span>上查看效果</p>

  <!-- JavaScript中使用data-*属性 -->
  <ul id="product-list">
    <li class="product" data-product-id="1" data-price="99.00" data-category="electronics" data-in-stock="true">
      无线耳机 - 99.00元
    </li>
    <li class="product" data-product-id="2" data-price="199.00" data-category="electronics" data-in-stock="false">
      蓝牙音箱 - 199.00元(缺货)
    </li>
    <li class="product" data-product-id="3" data-price="59.00" data-category="accessories" data-in-stock="true">
      手机壳 - 59.00元
    </li>
  </ul>

  <div id="cart-info"></div>

  <script>
    // 事件委托:利用data-*属性传递数据
    document.getElementById('product-list').addEventListener('click', function(e) {
      var product = e.target.closest('.product');
      if (!product) return;

      var info = {
        id: product.dataset.productId,
        price: parseFloat(product.dataset.price),
        category: product.dataset.category,
        inStock: product.dataset.inStock === 'true'
      };

      var cartInfo = document.getElementById('cart-info');
      if (info.inStock) {
        cartInfo.textContent = '已添加:商品#' + info.id + ',价格:' + info.price + '元';
      } else {
        cartInfo.textContent = '商品#' + info.id + '暂时缺货';
      }
    });

    // data-*属性命名规则
    // 合法:data-id, data-user-name, data-my-long-attribute, data-123
    // 非法:data-myAttr(不要用驼峰), data-(不能只有前缀)
    // 保留:data-xml-*(XML相关保留)
  </script>
</body>
</html>

代码示例

示例1:属性操作综合演示

代码示例

<!DOCTYPE html>
<html lang="zh-CN">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>属性操作综合演示</title>
  <style>
    body { font-family: -apple-system, sans-serif; max-width: 800px; margin: 0 auto; padding: 20px; }
    .demo-area { border: 1px solid #ddd; border-radius: 8px; padding: 20px; margin: 16px 0; }
    .controls { margin: 12px 0; }
    .btn { padding: 6px 14px; border: none; border-radius: 4px; cursor: pointer; margin: 4px; }
    .btn-primary { background: #007bff; color: white; }
    .btn-success { background: #28a745; color: white; }
    .btn-danger { background: #dc3545; color: white; }
    .btn-warning { background: #ffc107; color: #333; }
    .attr-table { width: 100%; border-collapse: collapse; margin: 8px 0; }
    .attr-table th, .attr-table td { padding: 6px 10px; text-align: left; border-bottom: 1px solid #eee; }
    .attr-table th { background: #f5f5f5; }
    input, select { padding: 6px 10px; border: 1px solid #ddd; border-radius: 4px; margin: 4px; }
  </style>
</head>
<body>
  <h1>属性操作综合演示</h1>

  <div class="demo-area">
    <div id="target" class="box primary" title="目标元素" data-count="5" data-status="active" aria-label="演示元素">
      <h3>目标元素</h3>
      <p>这是一个用于演示属性操作的元素</p>
    </div>
  </div>

  <div class="controls">
    <h3>属性操作</h3>
    <input type="text" id="attr-name" placeholder="属性名">
    <input type="text" id="attr-value" placeholder="属性值">
    <button class="btn btn-primary" onclick="setAttr()">设置属性</button>
    <button class="btn btn-success" onclick="getAttr()">获取属性</button>
    <button class="btn btn-danger" onclick="removeAttr()">移除属性</button>
    <button class="btn btn-warning" onclick="hasAttr()">检测属性</button>
    <button class="btn" style="background:#6c757d;color:white" onclick="listAttrs()">列出所有属性</button>
  </div>

  <div id="result" style="background:#f5f5f5; padding:12px; border-radius:4px; margin:12px 0; font-family:monospace; min-height:60px;">
    操作结果将显示在这里
  </div>

  <h3>当前属性列表</h3>
  <table class="attr-table">
    <thead><tr><th>属性名</th><th>属性值</th><th>操作</th></tr></thead>
    <tbody id="attr-list"></tbody>
  </table>

  <script>
    var target = document.getElementById('target');
    var resultEl = document.getElementById('result');
    var attrListEl = document.getElementById('attr-list');

    function showResult(msg) {
      resultEl.textContent = msg;
    }

    function refreshAttrList() {
      attrListEl.innerHTML = '';
      var attrs = target.attributes;
      for (var i = 0; i < attrs.length; i++) {
        var tr = document.createElement('tr');
        var name = attrs[i].name;
        var value = attrs[i].value;
        tr.innerHTML = '<td>' + name + '</td>' +
          '<td>' + (value.length > 40 ? value.substring(0, 40) + '...' : value) + '</td>' +
          '<td><button class="btn btn-danger" style="padding:2px 8px;font-size:12px" onclick="removeAttrByName(\'' + name + '\')">删除</button></td>';
        attrListEl.appendChild(tr);
      }
    }

    function setAttr() {
      var name = document.getElementById('attr-name').value.trim();
      var value = document.getElementById('attr-value').value;
      if (!name) { showResult('请输入属性名'); return; }
      target.setAttribute(name, value);
      showResult('已设置属性:' + name + ' = ' + value);
      refreshAttrList();
    }

    function getAttr() {
      var name = document.getElementById('attr-name').value.trim();
      if (!name) { showResult('请输入属性名'); return; }
      var value = target.getAttribute(name);
      showResult(value !== null ? name + ' = ' + value : '属性 "' + name + '" 不存在');
    }

    function removeAttr() {
      var name = document.getElementById('attr-name').value.trim();
      if (!name) { showResult('请输入属性名'); return; }
      if (target.hasAttribute(name)) {
        target.removeAttribute(name);
        showResult('已移除属性:' + name);
        refreshAttrList();
      } else {
        showResult('属性 "' + name + '" 不存在');
      }
    }

    function hasAttr() {
      var name = document.getElementById('attr-name').value.trim();
      if (!name) { showResult('请输入属性名'); return; }
      showResult('属性 "' + name + '" ' + (target.hasAttribute(name) ? '存在' : '不存在'));
    }

    function listAttrs() {
      var attrs = target.attributes;
      var result = '共 ' + attrs.length + ' 个属性:\n';
      for (var i = 0; i < attrs.length; i++) {
        result += attrs[i].name + ' = ' + attrs[i].value + '\n';
      }
      showResult(result);
    }

    function removeAttrByName(name) {
      target.removeAttribute(name);
      showResult('已移除属性:' + name);
      refreshAttrList();
    }

    // 初始化属性列表
    refreshAttrList();
  </script>
</body>
</html>

示例2:data-*属性实现标签页切换

代码示例

<!DOCTYPE html>
<html lang="zh-CN">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>data-*属性实现标签页切换</title>
  <style>
    body { font-family: -apple-system, sans-serif; max-width: 700px; margin: 0 auto; padding: 20px; }
    .tabs { display: flex; border-bottom: 2px solid #ddd; }
    .tab-btn { padding: 10px 20px; border: none; background: none; cursor: pointer; font-size: 14px; border-bottom: 2px solid transparent; margin-bottom: -2px; transition: all 0.2s; }
    .tab-btn:hover { color: #007bff; }
    .tab-btn.active { color: #007bff; border-bottom-color: #007bff; font-weight: bold; }
    .tab-content { display: none; padding: 20px; border: 1px solid #ddd; border-top: none; border-radius: 0 0 8px 8px; }
    .tab-content.active { display: block; }
  </style>
</head>
<body>
  <h1>标签页切换</h1>

  <div class="tabs" id="tab-container">
    <button class="tab-btn active" data-tab="profile">个人资料</button>
    <button class="tab-btn" data-tab="settings">设置</button>
    <button class="tab-btn" data-tab="notifications">通知</button>
    <button class="tab-btn" data-tab="security">安全</button>
  </div>

  <div class="tab-content active" data-panel="profile">
    <h3>个人资料</h3>
    <p>用户名:张三</p>
    <p>邮箱:zhangsan@example.com</p>
  </div>

  <div class="tab-content" data-panel="settings">
    <h3>设置</h3>
    <p>主题:深色模式</p>
    <p>语言:中文</p>
  </div>

  <div class="tab-content" data-panel="notifications">
    <h3>通知</h3>
    <p>邮件通知:已开启</p>
    <p>推送通知:已关闭</p>
  </div>

  <div class="tab-content" data-panel="security">
    <h3>安全</h3>
    <p>两步验证:已启用</p>
    <p>最后登录:2024-01-15</p>
  </div>

  <script>
    var tabContainer = document.getElementById('tab-container');

    // 事件委托:利用data-tab属性识别标签
    tabContainer.addEventListener('click', function(e) {
      var btn = e.target.closest('.tab-btn');
      if (!btn) return;

      // 读取data-tab属性
      var tabId = btn.dataset.tab;

      // 切换标签按钮状态
      tabContainer.querySelectorAll('.tab-btn').forEach(function(b) {
        b.classList.remove('active');
      });
      btn.classList.add('active');

      // 切换内容面板:利用data-panel属性匹配
      document.querySelectorAll('.tab-content').forEach(function(panel) {
        if (panel.dataset.panel === tabId) {
          panel.classList.add('active');
        } else {
          panel.classList.remove('active');
        }
      });
    });
  </script>
</body>
</html>

示例3:属性与特性同步验证

代码示例

<!DOCTYPE html>
<html lang="zh-CN">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>属性与特性同步验证</title>
  <style>
    body { font-family: -apple-system, sans-serif; max-width: 800px; margin: 0 auto; padding: 20px; }
    table { width: 100%; border-collapse: collapse; margin: 16px 0; }
    th, td { padding: 8px 12px; text-align: left; border: 1px solid #ddd; }
    th { background: #f5f5f5; }
    .synced { color: green; }
    .not-synced { color: red; }
    .test-area { margin: 16px 0; padding: 16px; background: #f9f9f9; border-radius: 8px; }
  </style>
</head>
<body>
  <h1>属性与特性同步验证</h1>

  <div class="test-area">
    <input id="test-input" type="text" value="初始值">
    <div id="test-div" class="test-class" data-value="test"></div>
  </div>

  <h2>input元素同步测试</h2>
  <table>
    <thead>
      <tr><th>操作</th><th>getAttribute('value')</th><th>.value</th><th>是否同步</th></tr>
    </thead>
    <tbody id="input-tests"></tbody>
  </table>

  <h2>div元素同步测试</h2>
  <table>
    <thead>
      <tr><th>操作</th><th>getAttribute('class')</th><th>.className</th><th>是否同步</th></tr>
    </thead>
    <tbody id="div-tests"></tbody>
  </table>

  <script>
    var input = document.getElementById('test-input');
    var div = document.getElementById('test-div');
    var inputTests = document.getElementById('input-tests');
    var divTests = document.getElementById('div-tests');

    function addTestRow(tbody, operation, attrValue, propValue) {
      var synced = String(attrValue) === String(propValue);
      var tr = document.createElement('tr');
      tr.innerHTML = '<td>' + operation + '</td>' +
        '<td>' + attrValue + '</td>' +
        '<td>' + propValue + '</td>' +
        '<td class="' + (synced ? 'synced' : 'not-synced') + '">' +
        (synced ? '同步' : '不同步') + '</td>';
      tbody.appendChild(tr);
    }

    // Input测试
    addTestRow(inputTests, '初始状态',
      input.getAttribute('value'), input.value);

    input.value = '通过Property修改';
    addTestRow(inputTests, '设置 .value = "通过Property修改"',
      input.getAttribute('value'), input.value);

    input.setAttribute('value', '通过Attribute修改');
    addTestRow(inputTests, 'setAttribute("value", "通过Attribute修改")',
      input.getAttribute('value'), input.value);

    // Div测试
    addTestRow(divTests, '初始状态',
      div.getAttribute('class'), div.className);

    div.className = 'new-class';
    addTestRow(divTests, '设置 .className = "new-class"',
      div.getAttribute('class'), div.className);

    div.setAttribute('class', 'another-class');
    addTestRow(divTests, 'setAttribute("class", "another-class")',
      div.getAttribute('class'), div.className);
  </script>
</body>
</html>

浏览器兼容性

属性操作方法兼容性

方法/属性 Chrome Firefox Safari Edge IE
getAttribute 全部 全部 全部 全部 5+
setAttribute 全部 全部 全部 全部 5+
removeAttribute 全部 全部 全部 全部 5+
hasAttribute 全部 全部 全部 全部 8+
attributes 全部 全部 全部 全部 5+
dataset 8+ 6+ 5.1+ 12+ 11+
data-* 属性 全部 全部 全部 全部 全部

IE中的已知问题

问题 IE版本 描述
getAttribute返回Property值 IE7- 某些属性(如href)getAttribute返回完整URL而非原始值
setAttribute设置class IE7- 需要使用className Property代替
setAttribute设置style IE7- 需要使用style Property代替
setAttribute设置事件 IE7- 需要使用事件Property代替
dataset不支持 IE10- 需要使用getAttribute/setAttribute

注意事项与最佳实践

1. 何时使用Attribute vs Property

代码示例

// 推荐使用Property的场景:
element.id = 'myId';           // 标准属性
element.className = 'myClass'; // class属性
element.value = 'newValue';    // 表单值
element.checked = true;        // 布尔属性
element.disabled = true;       // 布尔属性
element.href = 'https://...';  // 链接地址

// 推荐使用Attribute的场景:
element.setAttribute('data-custom', 'value');  // 自定义属性
element.setAttribute('aria-label', '描述');     // ARIA属性
element.setAttribute('role', 'button');         // 角色属性
element.setAttribute('tabindex', '0');          // tabindex

// 必须使用Attribute的场景:
// 1. 获取HTML源代码中的原始值
var originalHref = element.getAttribute('href');  // 原始值
var propertyHref = element.href;                   // 完整URL

// 2. 自定义属性(非data-*)
element.setAttribute('my-custom-attr', 'value');

// 3. 检测属性是否存在
element.hasAttribute('disabled');

2. 布尔属性的正确处理

代码示例

<!DOCTYPE html>
<html lang="zh-CN">
<head>
  <meta charset="UTF-8">
  <title>布尔属性的正确处理</title>
</head>
<body>
  <input id="demo" type="checkbox">

  <script>
    var demo = document.getElementById('demo');

    // 正确:使用Property设置布尔属性
    demo.checked = true;       // 选中
    demo.checked = false;      // 取消选中
    demo.disabled = true;      // 禁用
    demo.disabled = false;     // 启用

    // 不推荐:使用Attribute设置布尔属性
    demo.setAttribute('checked', '');   // 可以工作但不直观
    demo.removeAttribute('checked');     // 取消选中

    // 检测布尔属性状态
    // 推荐:使用Property
    if (demo.checked) { /* 已选中 */ }
    if (demo.disabled) { /* 已禁用 */ }

    // 不推荐:使用Attribute
    if (demo.hasAttribute('checked')) { /* 不准确 */ }

    // 常见布尔属性列表:
    // checked, disabled, selected, readonly, required,
    // multiple, autofocus, autoplay, controls, loop,
    // muted, hidden, open (details), default
  </script>
</body>
</html>

3. data-*属性的最佳实践

代码示例

// 1. 命名使用小写字母和连字符
// 推荐:data-user-id, data-product-name
// 不推荐:data-userId, data-productName

// 2. 值始终是字符串,需要手动转换类型
var count = parseInt(element.dataset.count, 10);
var isActive = element.dataset.isActive === 'true';
var items = JSON.parse(element.dataset.items);

// 3. 不要存储大量数据
// data-*属性适合存储少量配置数据
// 大量数据应使用JavaScript变量或API获取

// 4. 不要存储敏感数据
// data-*属性在HTML源代码中可见,不应存储密码、令牌等

// 5. 利用CSS attr()函数
// 可以在CSS中使用data-*属性的值
// .tooltip::after { content: attr(data-tooltip); }

代码规范示例

属性操作规范

代码示例

<!DOCTYPE html>
<html lang="zh-CN">
<head>
  <meta charset="UTF-8">
  <title>属性操作规范</title>
</head>
<body>
  <div id="app"></div>

  <script>
    (function() {
      'use strict';

      // 1. 标准属性使用Property
      function configureElement(el, config) {
        el.id = config.id || '';
        el.className = config.className || '';
        el.title = config.title || '';
        el.tabIndex = config.tabIndex || 0;

        // 布尔属性
        if (config.disabled) el.disabled = true;
        if (config.hidden) el.hidden = true;
      }

      // 2. 自定义属性使用setAttribute
      function setCustomAttrs(el, attrs) {
        Object.keys(attrs).forEach(function(key) {
          el.setAttribute(key, attrs[key]);
        });
      }

      // 3. ARIA属性使用setAttribute
      function setAriaAttrs(el, ariaAttrs) {
        Object.keys(ariaAttrs).forEach(function(key) {
          el.setAttribute('aria-' + key, ariaAttrs[key]);
        });
      }

      // 4. data-*属性使用dataset
      function setDataAttrs(el, data) {
        Object.keys(data).forEach(function(key) {
          el.dataset[key] = data[key];
        });
      }

      // 使用示例
      var button = document.createElement('button');
      configureElement(button, {
        id: 'submit-btn',
        className: 'btn btn-primary',
        title: '提交表单'
      });
      setAriaAttrs(button, {
        label: '提交表单',
        describedby: 'submit-help'
      });
      setDataAttrs(button, {
        action: 'submit',
        formId: 'contact-form'
      });
      button.textContent = '提交';

      document.getElementById('app').appendChild(button);
    })();
  </script>
</body>
</html>

常见问题与解决方案

问题1:getAttribute('href')返回完整URL

症状: <a href="/page">getAttribute('href') 在IE7中返回完整URL。

解决方案:

代码示例

// 方案1:使用Property获取完整URL
var fullURL = link.href;  // "https://example.com/page"

// 方案2:使用getAttribute获取原始值(现代浏览器)
var originalHref = link.getAttribute('href');  // "/page"

// 方案3:如果需要兼容IE7,从完整URL中提取
function getOriginalHref(element) {
  var href = element.getAttribute('href');
  // IE7可能返回完整URL,需要处理
  if (href.indexOf(window.location.origin) === 0) {
    href = href.substring(window.location.origin.length);
  }
  return href;
}

问题2:dataset在IE10及以下不支持

解决方案:

代码示例

// 兼容性封装
function getData(element, key) {
  if (element.dataset) {
    return element.dataset[key];
  }
  return element.getAttribute('data-' + key.replace(/([A-Z])/g, '-$1').toLowerCase());
}

function setData(element, key, value) {
  if (element.dataset) {
    element.dataset[key] = value;
  } else {
    var attrName = 'data-' + key.replace(/([A-Z])/g, '-$1').toLowerCase();
    element.setAttribute(attrName, value);
  }
}

function removeData(element, key) {
  if (element.dataset) {
    delete element.dataset[key];
  } else {
    var attrName = 'data-' + key.replace(/([A-Z])/g, '-$1').toLowerCase();
    element.removeAttribute(attrName);
  }
}

问题3:setAttribute设置style和class在IE7中不工作

解决方案:

代码示例

// 不推荐(IE7不兼容)
element.setAttribute('style', 'color: red;');
element.setAttribute('class', 'my-class');

// 推荐(兼容所有浏览器)
element.style.color = 'red';
element.className = 'my-class';

总结

DOM属性操作是前端开发中的基础技能,理解属性与特性的区别以及各种操作方法的适用场景非常重要:

  1. getAttribute/setAttribute:操作HTML属性,值始终为字符串,适合自定义属性和ARIA属性

  2. removeAttribute:移除属性,布尔属性必须用此方法而非设为空

  3. hasAttribute:检测属性是否存在,布尔属性检测的正确方式

  4. attributes:获取所有属性集合,遍历属性时使用

  5. dataset:操作data-*自定义属性,驼峰命名,值始终为字符串

  6. data-*:HTML5自定义属性标准,适合存储元素级配置数据

  7. 属性vs特性:标准属性优先使用Property,自定义属性使用Attribute方法

正确使用这些方法,能够确保代码的兼容性、安全性和可维护性。

常见问题

问题1:getAttribute('href')返回完整URL?

症状: <a href="/page">getAttribute('href') 在IE7中返回完整URL。 解决方案:

问题2:dataset在IE10及以下不支持?

解决方案:

问题3:setAttribute设置style和class在IE7中不工作?

解决方案:

标签: DOM HTML 属性操作 样式操作 节点操作

本文由小确幸生活整理发布,转载请注明出处

本文涉及AI创作

内容由AI创作,请仔细甄别

list快速访问

上一篇: JS集成:HTML DOM选择元素 - 详细教程与实战指南 下一篇: JS集成:HTML DOM修改样式 - 详细教程与实战指南

poll相关推荐