0、寫在前面的話
自己對前端的東西一直不是很熟,現在開始要想辦法從前端各個地方去獲取想要的屬性值的時候,也基本是在網上現炒現賣,幾周下來,發現自己還是迷迷糊糊,可以算是一無所獲。
所以就抽時間,把這一塊的東西收集整理一下,免得每次為了得到一個值要上網查詢鼓搗一萬年,實在是浪費時間,知其然知其所以然,才能讓問題迎刃而解。
這篇博文應該說結構還不夠完整,有些知識點還沒提到,覆蓋的內容其實主要還是為了滿足我現在入門知識理解的一個需求,日后再進行完善吧,這里先貼一些相關概念的參考鏈接,以后方便參考和添加:
1、理解節點
HTML文檔中,所有內容都是 “節點”,是一個Element,這意味着:
- 整個文檔是一個文檔節點
- 每個 HTML 元素是元素節點
- HTML 元素內的文本是文本節點
- 每個 HTML 屬性是屬性節點
- 注釋是注釋節點
先看下面的片段:
<html>
<head>
<title>DOM 教程</title>
</head>
<body>
<h1>DOM 第一課</h1>
<p>Hello world!</p>
</body>
</html>
9
1
<html>
2
<head>
3
<title>DOM 教程</title>
4
</head>
5
<body>
6
<h1>DOM 第一課</h1>
7
<p>Hello world!</p>
8
</body>
9
</html>
從上面的 HTML 中:
- <html> 節點沒有父節點;它是根節點
- <head> 和 <body> 的父節點是 <html> 節點
- 文本節點 "Hello world!" 的父節點是 <p> 節點
並且:
- <html> 節點擁有兩個子節點:<head> 和 <body>
- <head> 節點擁有一個子節點:<title> 節點
- <title> 節點也擁有一個子節點:文本節點 "DOM 教程"
- <h1> 和 <p> 節點是同胞節點,同時也是 <body> 的子節點
並且:
- <head> 元素是 <html> 元素的首個子節點
- <body> 元素是 <html> 元素的最后一個子節點
- <h1> 元素是 <body> 元素的首個子節點
- <p> 元素是 <body> 元素的最后一個子節點
重點:
- 獲得的每個節點,都是一個HTML 對象!(點擊查看<tr>標簽代表的對象)都有屬性!
- HTML DOM 允許 JavaScript 改變 HTML 元素的內容
2、JS獲取節點
我們知道,HTML文檔載入瀏覽器后,會成為
Document對象,這個對象讓我們可以從腳本中對HTML頁面所有元素進行訪問,我們經常獲取元素使用的幾大方法:getElementById()、
getElementsByClassName、
getElementsByName()、getElementsByTagName()就歸屬其下,也是我們最常使用到的方法。
- getElementById() 根據id屬性
- getElementsByName() 根據name屬性
- getElementsByClassName 根據class的名稱
- getElementsByTagName() 根據標簽
2.1 獲取單一節點
我們用document.getElementById(id)這個方法舉例,因為是根據HTML中唯一的id來獲取,所以得到的是單一節點,這個節點實際就是一個對象,也就是說,這個方法返回的是一個HTML對象。
每個標簽的出現,都意味着有一個對應的對象被創建,比如 <select> 標簽的存在,意味着有一個 Select對象 誕生;<option> 標簽,意味着有一個 Option對象 誕生。
我們說過,每個節點,都是一個對象,是對象,就有屬性,所以我們想要獲取對應的值,你只要
找到了這個對象,完全可以到w3school上查看下這個對象有哪些屬性,直接調用就可以了。
實際上,很多屬性是大部分對象都有的,也是我們所常用的:
- id 該節點的id值
- value 該節點的value值
- text 節點的文本值
- name 節點的name,名稱
諸如此類,還有很多,具體的可以直接查詢手冊。
來看看示例,假如有下面的HTML片段,現在想獲取關於 “張三” 的各類信息:
<table class="manage-table space" id="dataTable">
<tr class="center">
<th rowspan="2">學號</th>
<th rowspan="2">姓名</th>
<th rowspan="2">性別</th>
<th colspan="3">班級</th>
<th colspan="2">選課情況</th>
</tr>
<tr class="center">
<th>類別</th>
<th>學屆</th>
<th>班號</th>
<th>選課數</th>
</tr>
<tr class="center" idx="89">
<td id="studentId" hidden="true">89</td>
<td>0001</td>
<td>張三</td>
<td><a>男</a></td>
<td id="classId" hidden="true">38</td>
<td>理科</td>
<td>1999</td>
<td>3</td>
<td>3</td>
</tr>
</table>
26
1
<table class="manage-table space" id="dataTable">
2
<tr class="center">
3
<th rowspan="2">學號</th>
4
<th rowspan="2">姓名</th>
5
<th rowspan="2">性別</th>
6
<th colspan="3">班級</th>
7
<th colspan="2">選課情況</th>
8
</tr>
9
<tr class="center">
10
<th>類別</th>
11
<th>學屆</th>
12
<th>班號</th>
13
<th>選課數</th>
14
</tr>
15
<tr class="center" idx="89">
16
<td id="studentId" hidden="true">89</td>
17
<td>0001</td>
18
<td>張三</td>
19
<td><a>男</a></td>
20
<td id="classId" hidden="true">38</td>
21
<td>理科</td>
22
<td>1999</td>
23
<td>3</td>
24
<td>3</td>
25
</tr>
26
</table>
先通過之前提到的,可以通過查看網上的文檔和瀏覽器的調試器來找元素的”位置“,最終通過遍歷定位到該行 tr :
var dataTable = document.getElementById("dataTable");
var zhangsan;
for(var x in dataTable.rows) {
for(var y in dataTable.rows[x].attributes) {
if(dataTable.rows[x].attributes[y].name === "idx"
&& dataTable.rows[x].attributes[y].value === "89") {
zhangsan = dataTable.rows[x];
}
}
}
10
1
var dataTable = document.getElementById("dataTable");
2
var zhangsan;
3
for(var x in dataTable.rows) {
4
for(var y in dataTable.rows[x].attributes) {
5
if(dataTable.rows[x].attributes[y].name === "idx"
6
&& dataTable.rows[x].attributes[y].value === "89") {
7
zhangsan = dataTable.rows[x];
8
}
9
}
10
}
寫到這里,需要注意一點,那就是 for in 這個循環遍歷,這個方法是將對象的所有屬性遍歷,我們知道,數組也是一個對象,索引視為其屬性,所以假如數組還有額外的屬性,遍歷會將該屬性輸出。
所以,上面的寫法實際上存在很大的問題,因為Array表面上看來只有索引,實際上因為原型繼承的關系,它還有很多
從父類繼承下來的屬性,在這里也會同時遍歷出來,如索引遍歷完后緊接着遍歷了其原型對象的屬性 item,這個屬性就沒有attributes屬性的,但是這里之所以沒有報錯,是因為JS的靈(缺)活(陷),直接表示出undefined,所以也在我們的if條件判斷中溜了過去。
正確的寫法怎么寫?就老老實實用for循環,后面的例子會再次提到,你只要知道
這樣寫是存在很大風險的,不要這樣做,然后繼續往下看就好。
另,ES6中引入的iterable類型對象可以使用 for of 方法規避這個問題,而且直接遍歷出元素,而不是索引這么麻煩。
回到正題,現在我們得到了這一排,也就是這個 tr,那么什么信息都可以得到了,比如每個單元格的文本內容:
for(var z in zhangsan.cells) {
console.log(zhangsan.cells[z].innerText);
}
3
1
for(var z in zhangsan.cells) {
2
console.log(zhangsan.cells[z].innerText);
3
}
注意 innerHTML 和 innerText 的區別,比如對應zhangsan性別的那欄單元格:
innerHTML --> "<a>男</a>"
innerText --> "男"
2.2 獲取多個節點
獲取多個節點的方法如 getElementsByClassName、getElementsByName()、getElementsByTagName() 等,其實也很簡單,無非是獲取到了HTML對象的集合,再根據情況遍歷使用就可以了。
比如:
var trs = document.getElementsByTagName("tr");
console.log(trs);

2.3 DOM方式的獲取
上面我們提到的獲取元素屬性等等的方式,實際上很粗暴,就是使用對象直接獲取其屬性,實際上,還可以使用DOM方法來獲取,而且是有一定區別的。
假如我們獲取到一個HTML對象,叫做htmlObj,現在我們要獲取它的id值:
htmlObj.id; //對象方式,直接獲取屬性
htmlObj.getAttribute("id"); //DOM方法
3
1
htmlObj.id; //對象方式,直接獲取屬性
2
3
htmlObj.getAttribute("id"); //DOM方法
如果你在瀏覽器調試的時候,沒有發現獲取的HTML對象有類似getAttribute()這種方法,別着急,如果你知道原型的概念,你可以順着它的 __proto__ 屬性延伸一直摸索,看到一個 ElementPrototype 的時候,這些方法就在里面。現在不理解沒關系,你只要知道
這些方法就是HTML DOM對象從上面繼承下來的,並不是你沒看見就沒有。
用實際點的例子來說明,還是接剛才zhangsan的HTML作為例子,這次不磨嘰,先拿到zhangsan看下屬性:
var dataTable = document.getElementById("dataTable");
console.log(dataTable);
var zhangsan = dataTable.rows[2];
console.log(zhangsan);
5
1
var dataTable = document.getElementById("dataTable");
2
console.log(dataTable);
3
4
var zhangsan = dataTable.rows[2];
5
console.log(zhangsan);
通過控制台的輸出,我們可以看到,對於一些常見的屬性,比如id、class等,我們可以確實可以使用 zhangsan.id 或者 zhangsan.className 來獲取得到。 可是我們的zhangsan還額外自定義了一個屬性idx,那么問題就來了。
問題就出在,這個idx屬性並沒有直接放在zhangsan這個對象下,而是作為attributes集合中的元素,所以之前我們沒有辦法直接使用如 zhangsan.idx 的方法獲取值,而是很麻煩地再次通過遍歷和條件判斷來進行定位。
而實際上,DOM對象有一個 getAttribute() 方法,可以通過屬性名來獲取屬性的值,所以之前我們定義zhangsan的方法,實際上可以改成這樣:
var dataTable = document.getElementById("dataTable");
console.log(dataTable);
var zhangsan;
for(var x in dataTable.rows) {
var person = dataTable.rows[x];
if(person.getAttribute("idx") === "89") {
zhangsan = person;
}
}
console.log(zhangsan);
13
1
var dataTable = document.getElementById("dataTable");
2
console.log(dataTable);
3
4
var zhangsan;
5
6
for(var x in dataTable.rows) {
7
var person = dataTable.rows[x];
8
if(person.getAttribute("idx") === "89") {
9
zhangsan = person;
10
}
11
}
12
13
console.log(zhangsan);
很不幸,會報出 person.getAttribute() is not a function 的錯誤,why?之前提到過,for in 會遍歷其所有屬性,在遍歷完索引以后,它繼續遍歷那些從父類繼承下來的屬性,某些屬性並不是DOM對象,是沒有getAttribute方法的,循環到這里的時候,自然就報錯了。
所以我們還是老老實實使用for循環:
for(var x = 0; x < dataTable.rows.length; x++ ){
if(dataTable.rows[x].getAttribute("idx") === "89") {
zhangsan = dataTable.rows[x];
}
}
x
1
for(var x = 0; x < dataTable.rows.length; x++ ){
2
if(dataTable.rows[x].getAttribute("idx") === "89") {
3
zhangsan = dataTable.rows[x];
4
}
5
6
}
或者把之前的方法改一下,找到了以后就讓循環break,不再遍歷后面的元素:
for(var x in dataTable.rows) {
var person = dataTable.rows[x];
if(person.getAttribute("idx") === "89") {
zhangsan = person;
break;
}
}
7
1
for(var x in dataTable.rows) {
2
var person = dataTable.rows[x];
3
if(person.getAttribute("idx") === "89") {
4
zhangsan = person;
5
break;
6
}
7
}
或者把繼承的屬性篩掉不要:
for(var x in dataTable.rows) {
if(dataTable.rows.hasOwnProperty(x)){
var person = dataTable.rows[x];
if(person.getAttribute("idx") === "89") {
zhangsan = person;
}
}
}
8
1
for(var x in dataTable.rows) {
2
if(dataTable.rows.hasOwnProperty(x)){
3
var person = dataTable.rows[x];
4
if(person.getAttribute("idx") === "89") {
5
zhangsan = person;
6
}
7
}
8
}
這下,就正確了,代碼也簡單了好多,就是利用DOM方法,所以在特別是使用一些自定義標簽的時候,使用DOM的方法可以更加便捷。
3、jQuery獲取
3.1 認識jQuery的基本概念
我們都知道jQuery是一個JS函數庫,我們也知道jQuery可以更少的代碼做更多的事,我們還知道用jQuery獲取節點都是通過 $(selector) 的方式。可是,這里的$號什么意思呢?
JS世界中,變量命名的規范里,$是屬於合法的標識符的,
jQuery的函數有兩個名字,一個叫 jQuery,另一個就叫 $。所以實際上 $.ajax(options) 和 jQuery.ajax(options) 是等同的,你可以用瀏覽器的調試器,到控制台中去輸入 $===jQuery,結果會得到 true。
我們都知道JS中函數也是一個對象,所以這里的 $ 表示函數本身,如果是 $(),那么根據函數中return,你就會得到一個對象,我們常說是一個jQuery對象。
現在你不需要去深究太多,你只用知道常見的jQuery語法最終就是得到一個jQuery對象,這個對象看似和你通過document.getElementById之類的方法得到的東西一樣,實際上並不是,內容相似但完全是兩種不同的對象。所以,
jQuery對象沒辦法使用HTML DOM對象中的方法,比如 getAttribute ,同理
HTML DOM對象也無法使用jQuery對象的方法。
不過不用擔心,jQuery中封裝了大量的方法,可以替代HTML對象中的很多操作。比如 $("#foo").html(); 等同於 document.getElementById("foo").innerHTML;
3.2 jQuery對象和DOM對象的相互轉換
上面已經提到了,兩者是不同的對象,方法也不能共通,但是他們兩者之間是可以進行相互轉換的。
jQuery對象 --> DOM對象
var $cr=$("#cr"); //jquery對象
var cr = $cr[0]; //dom對象 jQueryObj[0]也可寫成 jQueryObj.get(0);
alert(cr.checked); //檢測這個checkbox是否給選中
3
1
var $cr=$("#cr"); //jquery對象
2
var cr = $cr[0]; //dom對象 jQueryObj[0]也可寫成 jQueryObj.get(0);
3
alert(cr.checked); //檢測這個checkbox是否給選中
DOM對象 --> jQuery對象
//只需要用$()把dom對象包裝起來
var cr=document.getElementById("cr"); //dom對象
var $cr = $(cr); //轉換成jquery對象
3
1
//只需要用$()把dom對象包裝起來
2
var cr=document.getElementById("cr"); //dom對象
3
var $cr = $(cr); //轉換成jquery對象
另外,從規范命名來講,如果獲取的對象是 jQuery對象,那么在
變量前面加上$,這樣方便容易識別出哪些是jQuery對象。
2018.03.22補充如下:
在項目中遇到了這樣的問題,有這樣一段代碼:
function loadLimit(trainingId, departmentId) {
var trs = $("#dataTable tr");
if (trs.length > 1) {
for (var i = 1; i < trs.length; i++) {
trs[i].remove();
}
}
$().invoke("/admin/elite/join/do/loadJoin.q", {trainingId:trainingId, departmentId:departmentId}, function(html) {
$("#dataTable").append($(html).find("tr"));
});
}
11
1
function loadLimit(trainingId, departmentId) {
2
var trs = $("#dataTable tr");
3
if (trs.length > 1) {
4
for (var i = 1; i < trs.length; i++) {
5
trs[i].remove();
6
}
7
}
8
$().invoke("/admin/elite/join/do/loadJoin.q", {trainingId:trainingId, departmentId:departmentId}, function(html) {
9
$("#dataTable").append($(html).find("tr"));
10
});
11
}
這段代碼在Chrome中運行正常,后來在IE中出錯,這才發現了問題。當時誤以為獲取的多標簽集合jQuery對象,其子元素也是jQuery對象,所以自然而然使用了remove(),實際上trs[i]獲得的已經是DOM對象,不支持jQuery方法,故報錯。我試着打印了結果,如下圖中,上為DOM對象,下為jQuery對象:

可以看到,jQuery對象中index為0的子元素,包含典型的innerHTML等屬性,這顯然是DOM對象的東西。也印證了之前寫過的筆記jQueyr對象轉DOM對象只需要類似var cr = $cr[0];即可。所以我自己的錯誤應該這樣修改:
$(trs[i]).remove();
1
1
$(trs[i]).remove();
亦或者有這樣的方法
eq(),表示將匹配元素集縮減值制定index上的一個:
trs.eq(i).remove();
1
1
trs.eq(i).remove();
3.3 jQuery的選擇器和方法
jQuery的選擇方式和CSS的選擇器方式類似,完整版你可以參考這里:(1)
jQuery的選擇器 (2)
jQuery 參考手冊 - 選擇器
至於jQuery的方法,還是直接丟鏈接比較方便:(1)
jQuery API 中文文檔 (2)
w3school的jQuery教程
3.4 jQuery選擇示例
還是zhangsan的例子,我們再貼一次代碼,免得拉上去再看:
<table class="manage-table space" id="dataTable">
<tr class="center">
<th rowspan="2">學號</th>
<th rowspan="2">姓名</th>
<th rowspan="2">性別</th>
<th colspan="3">班級</th>
<th colspan="2">選課情況</th>
</tr>
<tr class="center">
<th>類別</th>
<th>學屆</th>
<th>班號</th>
<th>選課數</th>
</tr>
<tr class="center" idx="89">
<td id="studentId" hidden="true">89</td>
<td>0001</td>
<td>張三</td>
<td><a>男</a></td>
<td id="classId" hidden="true">38</td>
<td>理科</td>
<td>1999</td>
<td>3</td>
<td>3</td>
</tr>
</table>
26
1
<table class="manage-table space" id="dataTable">
2
<tr class="center">
3
<th rowspan="2">學號</th>
4
<th rowspan="2">姓名</th>
5
<th rowspan="2">性別</th>
6
<th colspan="3">班級</th>
7
<th colspan="2">選課情況</th>
8
</tr>
9
<tr class="center">
10
<th>類別</th>
11
<th>學屆</th>
12
<th>班號</th>
13
<th>選課數</th>
14
</tr>
15
<tr class="center" idx="89">
16
<td id="studentId" hidden="true">89</td>
17
<td>0001</td>
18
<td>張三</td>
19
<td><a>男</a></td>
20
<td id="classId" hidden="true">38</td>
21
<td>理科</td>
22
<td>1999</td>
23
<td>3</td>
24
<td>3</td>
25
</tr>
26
</table>
我們要獲得zhangsan,用jQuery的方式就是:
var zhangsan = $("[idx='89']"); //表示通過屬性查找,屬性idx為89的
1
var zhangsan = $("[idx='89']"); //表示通過屬性查找,屬性idx為89的
沒錯,就是這么簡單...
然后你要么使用jQuery的一些方法來獲取里面的內容,或者粗暴地將它轉換為DOM對象再操作。