DOM (Document Object Model)

什么是 DOM?

第一章中,文中已通过代码演示了每个网页其实都是从HTML文件生成的。那么由各种标签组成的文件,最后又是如何以图像化的形式呈现在游览器中的呢?这就要提到 DOM 了,当游览器打开一份 HTML 文件时,会根据其文件的内容创建 DOM (Document Object Model),而 HTML DOM 就是由一些树状结构的 Objects 组成的:

创建好这颗 DOM 树后,游览器会根据每个节点之间的关系和其不同属性,进行界面的排序和渲染,最后才得到游览器上显示的最终界面。

所以一份 HTML 文件到可视化界面的顺序则是: 原HTML文件 –> HTML DOM –> GUI。也就是说我们最后的可视化界面是基于 HTML DOM 的,而DOM是从HTML文件中解析出来的。这就意味着,只要我们能够修改 HTML DOM,那么可视化界面就会发生改变,而 JavaScript 就能通过改动 DOM,动态改变前端的展示。

使用JavaScript控制DOM

JavaScript可以通过以下4种方式来控制HTML:

  • 使用id来找HTML元素
  • 使用tag名字来找HTML元素
  • 使用class名字来找HTML元素
  • 使用HTML object collections来找HTML元素

大家可以先创建以下这个 HTML 文件,然后通过在 console 中输入后面的 JavaScript 代码改变页面展示:

<!DOCTYPE html>
<html>
<head>
<style>
h1 { color: red; }
p { background-color: yellow; font-size: 20px;}
</style>
</head>
<body>
<h1 id='h1'>This is a Heading</h1>
<p>1st paragraph.</p>
<h1 class='c1'>This is another Heading</h1>
<p class='c1'>2nd paragraph.</p>
<a href="www.bilibili.com">Bilibili</a>
<a href="www.turingplanet.org">TuringPlanet</a>
</body>
</html>

使用 id 名字寻找 HTML 元素:

var head1 = document.getElementById("h1");
head1.innerHTML="New Heading";

使用 tab 名字找 HTML 元素:

var paragraphs = document.getElementsByTagName("p");
for (const p of paragraphs) {
   p.innerHTML = 'New Paragraph';
};

使用 class 名字来找 HTML 元素:

var p2 = document.getElementsByClassName("c1");
for (const obj of p2) {
   obj.style.background = "pink";
}

使用 CSS Selectors 来找 HTML 元素:

var x = document.querySelector("p.c1");
x.style.background = "yellow";

使用 HTML Object Collections 寻找 HTML 元素:

console.log(document.links.length);

以下是其他常用的 HTML Object Collections:

document.anchors
document.forms
document.images
document.links
document.scripts

JSON

JSON 的基本概念

了解完前端展示部分的内容,接下来,就来学习服务器和客户端之间用于传递数据的常用格式JSON。

JSON (JavaScript Object Notation)是一种轻量级的数据格式,常被前后端用于储存和传递数据。之所以现在 JSON 如此流行,除了用此方式存储的数据非常省空间,而且 JSON 形式的数据很 “self-describing”,非常便于理解。接下来看一看如何使用 JSON 格式表示由三个对象组成的 employees 数组:

{
"employees":[
    {"name":"Kevin", "age":"29"},
    {"name":"David", "age":"31"},
    {"name":"Peter", "age":"27"}
]
}

可见 JSON 非常便于理解的,其语法有以下4个特征:

  • 数据的存在形式:由名字和数值构成的数值对构成
  • 不同数据之间用逗号隔开
  • 尖括号 ( { } ) 用于储存对象(objects)
  • 方括号 ( [ ] ) 用于储存数组

JSON 数据的格式和 JavaScript 创建对象的格式一致,也正因为这种相似性,JavaScript 程序能很方便地将 JSON 数据转换成 JavaScript 对象。

JSON 中的数据是以数值对的形式存在的,单个数值对包含一个名字,连着冒号,再跟着名字对应的数值:

"name": "Kevin"

JSON 对象会被写入尖括号中,而一个对象可包含多个数值对:

{"name": "Kevin", "name": "David"}

JSON 数组则会被写在方括号中,数组中可包含多个对象:

"employees":[
    {"name":"Kevin", "age":"29"},
    {"name":"David", "age":"31"},
    {"name":"Peter", "age":"27"}
]

将 JSON 转换为 JavaScript 对象

正常情况下,客户端从服务器获取 JSON 数据,然后将其展示在前端网页上,为了简单演示 JSON 数据的易用性,可以在 JavaScript 中创建一个 JSON 格式的字符串:

var jsonText = '{ "employees" : [' +
'{ "name":"Kevin" , "age":"29" },' +
'{ "name":"David" , "age":"31" },' +
'{ "name":"Peter" , "age":"27" } ]}';

为了将 JSON 格式的字符串转换成 JavaScript 对象,可以直接使用 JavaScript 中的内置方法 JSON.parse():

var jsonObject = JSON.parse(jsonText);

当 text 被转换成 JavaScript 对象后,就能使用 JavaScript 直接控制对象的内容了,以下 html 文件就能提取 JSON 数据中的第一个员工名展示出来:

<!DOCTYPE html>
<html>
<body>
<h2>Create Object from JSON String</h2>
<p id="demo"></p>
<script>
var jsonText = '{ "employees" : [' +
'{ "name":"Kevin" , "age":"29" },' +
'{ "name":"David" , "age":"31" },' +
'{ "name":"Peter" , "age":"27" } ]}';

jsonObject = JSON.parse(jsonText);
document.getElementById("demo").innerHTML =
jsonObject.employees[1].name + " " + jsonObject.employees[1].age;
</script>

</body>
</html>

了解完 JSON 的基本概念,接下来学习在前端中如何获取后端数据来改变前端展示。

AJAX (Asynchronous JavaScript and XML)

什么是 AJAX?

AJAX 是 Asynchronous JavaScript and XML 的缩写,代表了一系列用来构建网站程序的技术。通过 AJAX 技术,网络程序能从客户端发出并获取服务器的数据,在不更新当前网站的情况下,自动重新加载其展示内容。

在传统 Web 应用中,用户先填写表单 (form),在填交表单后向服务器发送一个请求,然后服务器接收并处理传来的表单,最后返回一个新的网页。这种传统方式会浪费很多宽带资源,因为前后两个网页中大部分 HTML 代码往往是相同的,而且回应时间也会比较慢。

而 AJAX 应用可以仅向服务器发送并获取必要的数据,然后在客户端使用 JavaScript 处理来自服务器的回应。这样服务器和游览器之间需要交互的数据大大减少,回应速度也快了,前端页面的生成工作也交给客户端完成,让服务器的负荷也少了。

AJAX 不仅仅指单一的技术,而是由一系列相关的技术组成的。表达信息的部分会使用到 HTML 和 CSS,而 JavaScript 则被用来动态操作 DOM,被交换数据的形式一般是 XML 和 JSON 的形式(如今数据格式主要是 JSON 格式,用于减少数据储存量)。

如何使用 AJAX?

使用 AJAX 的特点就是在不更新网页的情况下,自动从服务器处获得数据,然后使用新数据更新网页前端。

现在互联网上有许多公开的 API,用于获取一些演示数据。推荐一个免费的网站叫做 jsonplaceholder,他们提供很多免费的 json 数据,在接下来的演示中会使用以下这个 API 获取一些演示用的 post:

https://jsonplaceholder.typicode.com/posts/

大家可以使用游览器打开这个链接,则会看到一个数组,其中每个 object 都是单个 post 的具体信息(user id, post id, title, body):

[
  {
    "userId": 1,
    "id": 1,
    "title": "sunt aut facere repellat provident occaecati excepturi optio reprehenderit",
    "body": "quia et suscipit\nsuscipit recusandae consequuntur expedita et cum\nreprehenderit molestiae ut ut quas totam\nnostrum rerum est autem sunt rem eveniet architecto"
  },
  {
    "userId": 1,
    "id": 2,
    "title": "qui est esse",
    "body": "est rerum tempore vitae\nsequi sint nihil reprehenderit dolor beatae ea dolores neque\nfugiat blanditiis voluptate porro vel nihil molestiae ut reiciendis\nqui aperiam non debitis possimus qui neque nisi nulla"
  },
  {
    "userId": 1,
    "id": 3,
    "title": "ea molestias quasi exercitationem repellat qui ipsa sit aut",
    "body": "et iusto sed quo iure\nvoluptatem occaecati omnis eligendi aut ad\nvoluptatem doloribus vel accusantium quis pariatur\nmolestiae porro eius odio et labore et velit aut"
  },
  ...
]

接下来就使用 AJAX 从网页中获取其API中的数据,然后动态更新网页:

<!DOCTYPE html>
<html>
  <head>
    <script>
    function loadJSON() {
      var xhttp = new XMLHttpRequest();
      xhttp.onreadystatechange = function() {
        if (this.readyState == 4 && this.status == 200) {
          displayData(this);
        }
      };
      xhttp.open("GET", "https://jsonplaceholder.typicode.com/posts/", true);
      xhttp.send();
    }
    function displayData(xhttp) {
      jsonData = JSON.parse(xhttp.responseText);
      var newContent = "" 
      for (index in jsonData) {
        newContent += "<p>" + jsonData[index].body + "</p>";
      }
      document.getElementById("json-content").innerHTML = newContent;
    }
    function clearJSON() {
      document.getElementById("json-content").innerHTML = "";
    }
    </script>
  </head>

  <body>
    <h2>AJAX DEMO</h2>
    <button type="button" onclick="loadJSON()">Get JSON</button>
    <button type="button" onclick="clearJSON()">Clear JSON</button>
    <div id="json-content"></div>
  </div>
  </body>
</html>

此网页中有两个按钮,第一个按钮 (GET JSON) 能自动抓取那些 posts,然后创建一系列的 paragraph,每段包含了单个 post 对象中的 body,并将这些段落放到 id 为 json-content 的 div 中,而另外一个按钮 (Clear JSON) 则会清空所有数据。

按下第一个按钮获取数据,并更新界面后,大家会发现网页并没有被重新加载,只有 <div> 的部分被更新,用户体验会更好,这就是 AJAX 的特点所在。

学完了前后端交互的重要概念后,下一章就开始学习如何在自己的服务器上创建输出 JSON 数据的 API,学完后大家就能彻底明白前后端之间的交互逻辑了。

实践练习

请尝试使用 gorest 网站来获取 JSON 数据,以下这个 API 可以获取一些案例用户的信息:

https://gorest.co.in/public-api/users

请用游览器打开此 API,并理解其 JSON 数据的存储方法,并创建一个 HMLT 文件将 API 中所有的用户名以 list 的形式显示出来。

<!DOCTYPE html>
<html>
  <head>
    <script>
    function loadJSON() {
      var xhttp = new XMLHttpRequest();
      xhttp.onreadystatechange = function() {
        if (this.readyState == 4 && this.status == 200) {
          displayData(this);
        }
      };
      xhttp.open("GET", "https://gorest.co.in/public-api/users", true);
      xhttp.send();
    }
    function displayData(xhttp) {
      jsonData = JSON.parse(xhttp.responseText);
      var newContent = "" 
      console.log(jsonData.data)
      for (index in jsonData.data) {
        newContent += "<p>" + jsonData.data[index].name + "</p>";
      }
      document.getElementById("json-content").innerHTML = newContent;
    }
    function clearJSON() {
      document.getElementById("json-content").innerHTML = "";
    }
    </script>
  </head>

  <body>
    <h2>AJAX DEMO</h2>
    <button type="button" onclick="loadJSON()">Get User Names</button>
    <button type="button" onclick="clearJSON()">Clear JSON</button>
    <div id="json-content"></div>
  </div>
  </body>
</html>