# JavaScript | HTML DOM 拓展内容

一些关于 HTML DOM 的拓展内容。

# 目录




# DOM 动画

JavaScript 提供了一个定时器 setInterval() 的方法,可以用来制作简易的动画。

注意

本段的 DOM 动画 Demo 仅用来加深对 JavaScript 与 DOM 的理解,实际情况下直接修改 DOM 会产生很大的性能问题,故不推荐使用此方法制作动画。


首先,创建一个 HTML 页面,使用一层 div 作为容器元素包裹 div 动画元素。

<!DOCTYPE html>
<html>
<body>

<h1>我的第一部 JavaScript 动画</h1>

<div id ="container">
  <div id="animation">我的动画在这里。</div>
</div>

</body>
</html>

然后添加样式:

#container {
  width: 400px;
  height: 400px;
  position: relative;
  background: gray;
}
#animate {
  width: 50px;
  height: 50px;
  position: absolute;
  background: orange;
}

然后使用 JavaScript,思路是借助定时器,每隔一段时间执行一次移动任务,当间隔时间足够短时动画看起来便足够连贯。

setInterval 的语法:

setInterval(code,millisec[,"lang"])

code 为每次执行的代码串(函数),millisec 为执行 code 的时间周期(毫秒单位)。

常用的解构如下:

var id = setInterval(frame, 5);

function frame() {
    if (/* 测试是否完成 */) {
        clearInterval(id);    // 调用后,停止 id 计时器
    } else {
         /* 改变元素样式的代码 */
    }
}

最后完成的动画 Demo 如下:

<!DOCTYPE html>
<html>
<style>
#container {
  width: 400px;
  height: 400px;
  position: relative;
  background: gray;
}
#animate {
  width: 50px;
  height: 50px;
  position: absolute;
  background: orange;
}
</style>
<body>

<p><button onclick="myMove()">单击此处</button></p>

<div id ="container">
  <div id ="animate"></div>
</div>

<script>
function myMove() {
  var elem = document.getElementById("animate");
  var pos = 0;
  var id = setInterval(frame, 5);
  function frame() {
    if (pos == 350) {
      clearInterval(id);
    } else {
      pos++;
      elem.style.top = pos + "px";
      elem.style.left = pos + "px";
    }
  }
}
</script>

</body>
</html>

# 属性与特性

当浏览器加载页面时,它会解析 HTML 文本并生成 DOM 对象。对于元素节点,大多数 HTML 特性(attribute)会自动变成 DOM 对象的属性(property)。比如一个标签是 <body id="page">,那么 DOM 对象会生成这样一个属性 body.id="page",我们称这个特性是标准化特性。

但是特性与属性并不总是一一对应的。当一个特性(假设为 something)是非标准的时候,它会作为特性而不会转为属性,此时我们无法使用 elem.something 去访问它,但可以调用方法去获得、修改、删除特性。

# 方法

方法 / 属性 描述
elem.hasAttribute(name) 检查是否存在这个特性
elem.getAttribute(name) 获取这个特性
elem.setAttribute(name, value) 把这个特性设置为 name 值
elem.removeAttribute(name) 移除这个特性
elem.attributes 所有特性的集合

# 对比

类型 名字
属性 property 属性值 键名大小写敏感
特性 attribute 字符串 键名大小写不敏感

一般来说,标准化的特性被改变的时候能够自动同步到属性,反之亦然。但对于特殊情况,只能从特性同步到属性,如 inputvalue

<input>

<script>
  let input = document.querySelector('input');

  // 特性 => 属性
  input.setAttribute('value', 'text');
  alert(input.value); // text

  // 属性 => 特性 操作无效
  input.value = 'newValue';
  alert(input.getAttribute('value')); // text(没有更新)
</script>

虽然特性都是字符串,但是转换过来的属性可能是布尔值、对象甚至和原来都不是同一种内容的东西, 例如:DOM 属性 href 总是存储绝对路径,而特性值 href 可能只包含相对路径或者只包含 #hash 部分。

# 特性使用场景

借助非标准特性,我们可以给 HTML 元素打上“标记”。

<!-- 标记这个 div 中要显示 "name" -->
<div show-info="name"></div>
<!-- 这里要显示 "age" -->
<div show-info="age"></div>

<script>
  // 这段代码是找到该元素并且按照给定数据展示到页面上
  let user = {
    name: "Pete",
    age: 25
  };

  for(let div of document.querySelectorAll('[show-info]')) {
    // 插入相应的数据
    let field = div.getAttribute('show-info');
    div.innerHTML = user[field]; // Pete,然后是年龄
  }
</script>

还可以应用于元素的样式上:

<style>
  /* 按照 "order-state" 的设定产生对应样式 */
  .order[order-state="new"] {
    color: green;
  }

  .order[order-state="pending"] {
    color: blue;
  }

  .order[order-state="canceled"] {
    color: red;
  }
</style>

<div class="order" order-state="new">
  A new order.
</div>

<div class="order" order-state="pending">
  A pending order.
</div>

<div class="order" order-state="canceled">
  A canceled order.
</div>

那么,为什么使用特性而不直接设置class / id?因为特性值更容易管理,我们可以轻易的通过特性值的改变切换样式,比如下面这样:

// 可以轻易的移除或者添加一个新的类名。
div.setAttribute('order-state', 'canceled');

# 特性合法化

虽然特性十分便利,但是自定义特性也存在问题:如果一个非标准化的特性在日后因为 HTML 标准的改变而标准化了(因为既然经常出现某一个非标准的特性,说明其好用,所以就会考虑将其标准化),这样就会出现问题。

为此 HTML 标准规定了所有以“data-”开头的特性值都可以正常使用,同时还会被作为 dataset 的合法值,可读可写。

例如:

<body data-about="Elephants">
<script>
  alert(document.body.dataset.about); // Elephants
</script>

而由横线连接的变量名可以写成驼峰式:

<div data-order-state="new">
  A new order.
</div>

<script>
  alert(order.dataset.orderState);  // new
</script>

# 什么时候使用

对于大多数需求,DOM 属性已经可以给予很好的支持。应当在 DOM 属性实在无法满足开发需求的情况下才使用特性,比如以下情况:

  • 我们需要一个非标准化的特性。
    不过,如果使用 data- 来设置特性值,就可以 dataset 来获取属性值。
  • 我们想要读取到 HTML 的展示内容。
    比如 href 属性总是一个绝对路径,但是我们只想要相对路径。
上次更新: 2020/2/16 15:06:54