文檔邏輯結(jié)構(gòu)
DOM基礎概念、操作
DOM是什么
DOM全稱為The Document Object Model,應該理解為是一個規(guī)范,定義了HTML和XML文檔的邏輯結(jié)構(gòu)和文檔操作的編程接口。
文檔邏輯結(jié)構(gòu)
DOM實際上是以面向?qū)ο蠓绞矫枋龅膶ο竽P?,它將文檔建模為一個個對象,以樹狀的結(jié)構(gòu)組織(本文稱之為“文檔樹”,樹中的對象稱為“節(jié)點”)。
每個文檔包含1個document節(jié)點,0個或1個doctype節(jié)點以及0個或多個元素節(jié)點等。document節(jié)點是文檔樹的根節(jié)點。
如對于HTML文檔,DOM 是這樣規(guī)定的:
整個文檔是一個文檔節(jié)點
每個 HTML 標簽是一個元素節(jié)點
包含在 HTML 元素中的文本是文本節(jié)點
每一個 HTML 屬性是一個屬性節(jié)點
注釋屬于注釋節(jié)點
節(jié)點與文檔內(nèi)容是一一對應的關系,節(jié)點之間有層次關系。
例如下面的html文檔:
<!DOCTYPE html>
<html>
<head>
<title>文檔標題</title>
</head>
<body>
<a href="">我的鏈接</a>
<h1>我的標題</h1>
</body>
</html>
[圖片上傳失敗...(image-2c214-1530240178333)]
nodeType
元素.nodeType:只讀 屬性 當前元素的節(jié)點類型
DOM節(jié)點的類型nodeType一種有12種,可以查看這里。
常用的節(jié)點類型包括:元素節(jié)點、文本節(jié)點、屬性節(jié)點:
元素節(jié)點 ELEMENT_NODE:1
屬性節(jié)點 ATTRIBUTE_NODE :2
文本節(jié)點 TEXT_NODE:3
<ul id="ul1" style="color: green">
<li>1111</li>
<li>1111</li>
<li>1111</li>
<li>1111</li>
</ul>
oUl = document.getElementById('ul1');
alert(oUl.nodeType); // 彈出1
alert(oUl.childNodes[0].nodeType); //彈出3
alert(oUl.attributes[0].nodeType); //彈出2
alert(oUl.attributes[0].name); //彈出'id'
alert(oUl.attributes.length); //彈出2
alert(oUl.attributes[0].value); //彈出'ul1'
attributes
元素.attributes:只讀 屬性 屬性列表集合
具體代碼可以查看NodeType中js代碼中alert的部分。
DOM節(jié)點
childNodes \ children
獲取第一級子元素
有兼容性問題(空白節(jié)點),nodeType屬性
firstChild \ firstElementChild
獲取子元素里的第一個
lastChild \ lastElementChild
獲取子元素里的最后一個
childNodes
元素.childNodes:只讀屬性 子節(jié)點列表集合
childNodes至包含一級子節(jié)點,不包含后輩孫級以下的節(jié)點
childNodes的兼容性問題:
標準瀏覽器下:childNodes包含了文本和元素類型的節(jié)點,并且也會包含非法嵌套的子節(jié)點;
非標準瀏覽器下,至包含元素類型的節(jié)點,IE7及以下不包含非法嵌套的子節(jié)點
oUl = document.getElementById('ul1');
alert(oUl.childNodes.length); //在標準瀏覽器下彈出9;在IE6、7彈出4。因為標準瀏覽器下,文本元素(在這里是換行符)也包含在childNodes里面了。
for (var i=0; i<oUl.childNodes.length; i++){
oUl.childNodes[i].style.background = 'red'; //在標準瀏覽器下會報錯,因為文本元素(這里是換行符)沒有是沒有style屬性的。
}
//可以通過下面這種方式來解決:
for (var i=0; i<oUl.childNodes.length; i++){
if (oUl.childNodes[i].nodeType == 1) {
oUl.childNodes[i].style.background = 'red';
}
}
children
元素.children:只讀 屬性 子節(jié)點列表集合
標準下: 只包含元素類型的節(jié)點,并且包含非法嵌套的子節(jié)點
非標準下:只包含元素類型的節(jié)點,IE7及以下不包含非法嵌套的子節(jié)點
這樣,如果把childNodes換為children的話,就不用進行nodeType的判斷了。
for (var i=0; i<oUl.children.length; i++){
oUl.children[i].style.background = 'red';
}
子節(jié)點和兄弟節(jié)點的操作
firstChild
元素.firstChild:只讀 屬性 第一個子節(jié)點
標準下:firstChild會包含文本類型的節(jié)點
非標準下: 只包含元素節(jié)點
firstElementChild
元素.firstElementChild:只讀 屬性
標準下獲取第一個元素類型節(jié)點的子節(jié)點
非標準瀏覽器不支持
因此要進行判斷:
if (oUl.firstElementChild){
oUl.firstElementChild.style.background = 'red';
} else {
oUl.firstChild.style.background = 'red';
}
//更為簡潔的寫法:
var oFirst = oUl.firstElementChild || oUl.firstChild;
oFirst.style.background = 'red';
lastChild、lastElementChild
元素.lastChild
元素.lastElementChild 最后一個子節(jié)點
原理與firstChild
firstElementChild相似,不再贅述
nextSibling、previousSibling
元素.nextSibling
元素.nextElementSibling 下一個兄弟節(jié)點
元素.previousSibling
元素.previousElementSibling 上一個兄弟節(jié)點
父節(jié)點
parentNode
<ul id="ul1">
<li>1111 <a href="javascript:;">隱藏</a></li>
<li>2222 <a href="javascript:;">隱藏</a></li>
<li>3333 <a href="javascript:;">隱藏</a></li>
<li>4444 <a href="javascript:;">隱藏</a></li>
</ul>
var oA = document.getElementsByTagName('a');
for (var i=0; i<oA.length; i++){
oA[i].onclick = function(){
this.parentNode.style.display = 'none';
}
}
元素.parentNode: 只讀 屬性 只有一個 當前節(jié)點的父級節(jié)點
offsetParent
<head>
<style>
div {padding: 40px 50px;}
#div1 {background: red;}
#div2 {background: green;}
#div3 {background: orange;}
</style>
</head>
<body id="body1">
<div id="div1">
<div id="div2">
<div id="div3"></div>
</div>
</div>
</body>
var oDiv3 = document.getElementById('div3');
alert(oDiv3.parentNode.id); //彈出div2
alert(oDiv3.offsetParent.id); //彈出body1
上面的代碼,如果給div1的style里面加上position: relative; 那么div3的offsetParent就變成了div1
元素.offsetParent:只讀 屬性 離當前元素最近的一個有定位的父節(jié)點
如果沒有定位父級,默認是body
操作元素屬性的多種方式
點的形式和中括號形式
通過.點的形式:oText.value
通過中括號[]的形式:oText[‘value’] (當屬性名用變量來表示的時候,用中括號)
getAttribute、setAttribute、removeAttribute
元素.getAttribute(屬性名稱); 方法 獲取指定元素的指定屬性的值
元素.setAttribute(屬性名稱, 屬性值); 方法 給指定元素指定的屬性設置值
元素.removeAttribute(屬性名稱); 方法 移除指定的元素的指定的屬性
set/get與用點.的區(qū)別:
用.和[]的形式無法操作元素的自定義屬性;getAttribute可以操作元素的自定義屬性
用.和[]的形式來獲取src的時候,獲取的是一長串絕對路徑,但是在IE8以上以及標準瀏覽器中,用getAttribute(‘src’)可以獲取到相對路徑(但是在IE7及以下,獲取的src還是絕對路徑)
元素的創(chuàng)建操作
document.createElement();
document.createElement(標簽名);
動態(tài)創(chuàng)建元素
不會直接顯示在頁面當中
前面必須是document,不能是其他
appendChild()
父級.appendChild(要追加的元素)
<!DOCTYPE html>
<html lang="en">
<head>
<style>
div {
padding: 40px 50px;
}
#div1 {
background: red;
position: relative;
}
#div2 {
background: green;
position: relative;
}
#div3 {
background: orange;
}
</style>
<script>
window.onload = function () {
var btn = document.getElementById('btn');
var ul = document.getElementById('ul');
btn.onclick = function () {
var li = document.createElement('li');//<li></li>
li.innerHTML = 'zhangsan';
ul.appendChild(li)
}
}
</script>
</head>
<body id="body1">
<button id="btn">娣誨姞li</button>
<ul id="ul">
</ul>
</body>
</html>
方法
在指定父級子節(jié)點最后一個后面追加子元素
insertBefore()
父級.insertBefore(新的元素,指定的被插入的元素);
方法
在父級的指定子元素前面插入一個新元素
在IE下,如果第二個參數(shù)的節(jié)點不存在,會報錯
在其它標準瀏覽器下,如果第二個參數(shù)的節(jié)點不存在,則會以appendChild的方式進行添加
removeChild()
父級.removeChild(要刪除的節(jié)點);
或者 元素.remove();
replaceChild()
父級.replaceChild(新節(jié)點、被替換節(jié)點) 替換子節(jié)點
appendChild,insertBefore,replaceChild可以操作靜態(tài)節(jié)點,也可以操作動態(tài)生成的節(jié)點。
window.onload = function () {
var btn = document.getElementById('btn');
var ul = document.getElementById('ul');
var content = document.getElementById('text');
btn.onclick = function () {
var li = document.createElement('li');//<li></li>
li.innerHTML = content.value;
var a = document.createElement('a');
a.href = '#';
a.innerHTML = 'Delete';
a.onclick = function () {
this.parentNode.remove();
}
li.appendChild(a);
ul.appendChild(li);
}
}
表單操作
name
name:表單中可以通過name來獲取元素:父級.name (該方法瀏覽器都兼容)
onchange事件
onchange事件:當值發(fā)生改變的時候觸發(fā)
text:當光標離開的時候,如果內(nèi)容有變化,就觸發(fā)
radio/checkbox:
標準下點擊的時候,只要值發(fā)生改變,就會觸發(fā);
非標準下,焦點離開的時候,如果值發(fā)生改變就觸發(fā)
select:一選擇不同的項,就觸發(fā)
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<form id="form1">
<input type="text" name="text1" />
<input type="radio" name="sex" value="男" checked />男
<input type="radio" name="sex" value="女" />女
<input type="checkbox" name="a" value="html" checked />html
<input type="checkbox" name="a" value="css" />css
<input type="checkbox" name="a" value="javascript" />javascript
<select name="city">
<option value="">請選擇城市</option>
<option value="北京">北京</option>
<option value="上海">上海</option>
</select>
<input type="button" value="按鈕" name="btn" />
</form>
<script>
var oForm = document.getElementById('form1');
oForm.text1.onchange = function(){
alert(this.value); //注意,文本輸入框onchange的觸發(fā),是在輸入完畢之后,鼠標離開該文本框之后觸發(fā)
}
oForm.text1.oninput = function(){
condole.log(this.value);//輸入一個字符,輸出一個字符
}
oForm.sex[0].onchange = function(){
// alert(1);
// alert(this.value);
} //注意:oForm.sex其實是一個元素集合,因為name為sex的單選按鈕有兩個
oForm.a[0].onchange = function(){
alert(2);
}
// alert(oForm.city.value);
oForm.city.onchange = function(){
alert(this.value);
}
oForm.btn.onclick = function(){
//radio, checkbox 判斷當前的選項是否被選中
//alert(oForm.sex[0].checked);
for(var i=0; i<oFrom.sex.length; i++){
if(oForm.sex[i].checked){
alert(oForm.sex[i].value + '被選中了');
} else {
alert(oForm.sex[i].value + '未被選中');
}
}
for(var i=0; i<oFrom.a.length; i++){
if(oForm.a[i].checked){
alert(oForm.a[i].value + '被選中了');
} else {
alert(oForm.a[i].value + '未被選中');
}
}
}
</script>
</body>
</html>
表格操作
<table width="100%" id="tab1" border="1px">
<tr>
<td>1</td>
<td>leo</td>
<td>男</td>
<td><a href="javascript:;">刪除</a></td>
</tr>
<tr>
<td>1</td>
<td>小美</td>
<td>女</td>
<td><a href="javascript:;">刪除</a></td>
</tr></table>
var oTab = document.getElementById('tab1');
alert(oTab.children[1].children[1].innerHTML); //什么也彈不出來,提示顯示oTab.children[1]未定義,這是因為如果在table中沒有添加tbody的話,瀏覽器會自動隱形添加一個tbody出來。因此,寫表格結(jié)構(gòu)時,最好添加上tbody。
正確的做法
<table width="100%" id="tab1" border="1px">
<thead>
<tr>
<th>編號</th>
<th>姓名</th>
<th>性別</th>
<th>操作</th>
</tr>
</thead>
<tbody>
<tr>
<td>1</td>
<td>leo</td>
<td>男</td>
<td><a href="javascript:;">刪除</a></td>
</tr>
<tr>
<td>1</td>
<td>小美</td>
<td>女</td>
<td><a href="javascript:;">刪除</a></td>
</tr>
</tbody>
</table>
var oTab = document.getElementById('tab1');
// alert(oTab.children[0].children[1].children[1].innerHTML); //這是就可以彈出“小美”
alert(oTab.tBodies[0].rows[1].cells[1].innerHTML); //彈出小美,更為直觀
表格屬性
tHead:表格頭(DOM中規(guī)定thead只能有一個)
tBodies:表格正文(DOM中規(guī)定tbody可以有多個)
tFoot:表格尾(DOM中規(guī)定tfoot只能有一個)
rows:行
cells:列
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<table width="100%" id="tab1" border="1px">
<thead>
<tr>
<th>編號</th>
<th>姓名</th>
<th>性別</th>
<th>操作</th>
</tr>
</thead>
<tbody>
</tbody>
</table>
<script>
var data = [
{id: 1, username: 'leo', sex: '男'},
{id: 2, username: '小美', sex: '女'},
{id: 3, username: '王亮', sex: '男'},
{id: 4, username: 'zhangsan', sex: '男'}
];
var oTab = document.getElementById('tab1');
var oTbody = oTab.tBodies[0];
for(var i=0; i<data.length; i++){ //表格的創(chuàng)建
var oTr = document.createElement('tr');
if(i%2 == 0){ //各行變色
oTr.style.background = 'white';
} else {
oTr.style.background = 'gray';
}
var oTd = document.createElement('td');
oTd.innerHTML = data[i].id;
oTr.appendChild(oTd);
oTd = document.createElement('td');
oTd.innerHTML = data[i].username;
oTr.appendChild(oTd);
oTd = document.createElement('td');
oTd.innerHTML = data[i].sex;
oTr.appendChild(oTd);
oTd = document.createElement('td');
oTr.appendChild(oTd);
var oA = document.createElement('a');
oA.innerHTML = '刪除';
oA.href = 'javascript:;';
oA.onclick = function(){
oTbody.removeChild(this.parentNode.parentNode);
for(var i=0; i<oTbody.rows.length; i++){
if(i%2 == 0) {
oTbody.rows[i].style.background = 'white';
} else {
oTbody.rows[i].style.background = 'gray';
}
}
}
oTd.appendChild(oA);
oTbody.appendChild(oTr);
}
</script>
</body>
</html>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<script>
var data = [
{id: 1, username: 'leo', sex: '男',age:32},
{id: 2, username: '小美', sex: '女',age:32},
{id: 3, username: '王亮', sex: '男',age:32},
{id: 4, username: 'zhangsan', sex: '男',age:32},
{id: 5, username: 'dddd', sex: '男',age:32}
];
window.onload = function () {
// var obj = {id: 1, username: 'leo', sex: '男'};
// for(var p in obj)
// {
// alert(p);
// alert(obj[p]);
// }
var oTab = document.getElementById('tab1');
var oTbody = oTab.tBodies[0];
for(var i = 0; i < data.length; i++)
{
var tr = document.createElement('tr');//<tr></tr>
// var td1 = document.createElement('td');//<td></td>
// td1.innerText = data[i].id;
// tr.appendChild(td1);
// var td2 = document.createElement('td');//<td></td>
// td2.innerText = data[i].username;
// tr.appendChild(td2);
// var td3 = document.createElement('td');//<td></td>
// td3.innerText = data[i].sex;
// tr.appendChild(td3);
for(var p in data[i])//{id: 2, username: '小美', sex: '女'}
{
var td1 = document.createElement('td');//<td></td>
td1.innerText = data[i][p];
tr.appendChild(td1);
}
var td4 = document.createElement('td');//<td></td>
var a = document.createElement('a');
a.href = '#';
a.innerText = '刪除';
a.onclick = function () {
this.parentNode.parentNode.remove();
for(var j = 0; j < oTbody.rows.length; j++)
{
if(j % 2 != 0)
{
oTbody.rows[j].style.backgroundColor = 'blue';
}
else
{
oTbody.rows[j].style.backgroundColor = 'white';
}
}
}
td4.appendChild(a);
tr.appendChild(td4);
oTbody.appendChild(tr);
}
for(var j = 0; j < oTbody.rows.length; j++)
{
if(j % 2 != 0)
{
oTbody.rows[j].style.backgroundColor = 'blue';
}
else
{
oTbody.rows[j].style.backgroundColor = 'white';
}
}
}
</script>
</head>
<body>
<table width="100%" id="tab1" border="1px">
<thead>
<tr>
<th>編號</th>
<th>姓名</th>
<th>性別</th>
<th>年齡</th>
<th>操作</th>
</tr>
</thead>
<tbody>
<!--<tr>-->
<!--<td>1</td>-->
<!--<td>leo</td>-->
<!--<td>男</td>-->
<!--</tr>-->
</tbody>
</table>
</body>
</html>
<!DOCTYPE html>
<html>
<head>
<title>購物車</title>
<meta charset="utf-8" />
<style type="text/css">
h1 {
text-align:center;
}
table {
margin:0 auto;
width:60%;
border:2px solid #aaa;
border-collapse:collapse;
}
table th, table td {
border:2px solid #aaa;
padding:5px;
}
th {
background-color:#eee;
}
</style>
<script>
var map = new Map();//key:商品名,tr:購物車中的商品數(shù)量
function compute_total_price() {
var tbodys = document.getElementById('goods');
var sum = 0;
for(var i = 0; i < tbodys.rows.length; i++)
{
sum += parseInt(tbodys.rows[i].cells[3].innerText);
}
document.getElementById('total').innerText = sum;
}
function decrease(obj) {
var count = parseInt(obj.nextElementSibling.value);
if(count > 1)
{
count--;
}
else
{
del(obj.parentNode.parentNode.cells[4].children[0]);
}
obj.nextElementSibling.value = count;
compute_price(obj.nextElementSibling);
}
function increase(obj) {
var count = parseInt(obj.previousElementSibling.value);
count++;
obj.previousElementSibling.value = count;
compute_price(obj.previousElementSibling);
}
function del(obj) {
map.delete(obj.parentNode.parentNode.cells[0].innerText);
obj.parentNode.parentNode.remove();
compute_total_price();
}
function compute_price (obj) {
var count = parseInt(obj.value);
var price = parseInt(obj.parentNode.previousElementSibling.innerText);
var total_price = price * count;
obj.parentNode.nextElementSibling.innerText = total_price;
compute_total_price();
}
window.onload = function () {
var goods = document.getElementById('goods_list');
var tbody = document.getElementById('goods');
var inputs = goods.getElementsByTagName('input');
for(var i = 0; i < inputs.length;i++)
{
inputs[i].onclick = function () {
var good_name = this.parentNode.parentNode.cells[0].innerText;
if(map.has(good_name))
{
var tr = map.get(good_name);
var str_count = tr.cells[2].children[1].value;
var count = parseInt(str_count) + 1;
tr.cells[2].children[1].value = count;
compute_price(tr.cells[2].children[1]);
}
else
{
var good_price = this.parentNode.parentNode.cells[1].innerText;
var cart_item = `
<td>${good_name}</td>
<td>${good_price}</td>
<td align="center">
<input type="button" value="-" onclick="decrease(this)"/>
<input type="text" size="3" value="1"/>
<input type="button" value="+" onclick="increase(this)"/>
</td>
<td>${good_price}</td>
<td align="center">
<input type="button" value="x" onclick="del(this)"/>
</td>
`;
var tr = document.createElement('tr')
tr.innerHTML = cart_item;
tbody.appendChild(tr);
map.set(good_name,tr);
compute_total_price();
}
}
}
}
</script>
</head>
<body>
<h1>真劃算</h1>
<table id="goods_list">
<tr>
<th>商品</th>
<th>單價(元)</th>
<th>顏色</th>
<th>庫存</th>
<th>好評率</th>
<th>操作</th>
</tr>
<tr>
<td>羅技M185鼠標</td>
<td>80</td>
<td>黑色</td>
<td>893</td>
<td>98%</td>
<td align="center">
<input type="button" value="加入購物車" />
</td>
</tr>
<tr>
<td>微軟X470鍵盤</td>
<td>150</td>
<td>黑色</td>
<td>9028</td>
<td>96%</td>
<td align="center">
<input type="button" value="加入購物車" />
</td>
</tr>
<tr>
<td>洛克iphone6手機殼</td>
<td>60</td>
<td>透明</td>
<td>672</td>
<td>99%</td>
<td align="center">
<input type="button" value="加入購物車" />
</td>
</tr>
<tr>
<td>藍牙耳機</td>
<td>100</td>
<td>藍色</td>
<td>8937</td>
<td>95%</td>
<td align="center">
<input type="button" value="加入購物車" />
</td>
</tr>
<tr>
<td>金士頓U盤</td>
<td>70</td>
<td>紅色</td>
<td>482</td>
<td>100%</td>
<td align="center">
<input type="button" value="加入購物車" />
</td>
</tr>
</table>
<h1>購物車</h1>
<table>
<thead>
<tr>
<th>商品</th>
<th>單價(元)</th>
<th>數(shù)量</th>
<th>金額(元)</th>
<th>刪除</th>
</tr>
</thead>
<tbody id="goods">
</tbody>
<tfoot>
<tr>
<td colspan="3" align="right">總計</td>
<td id="total"></td>
<td></td>
</tr>
</tfoot>
</table>
</body>
</html>