一、DOM簡介
1.什麼是DOM
文檔對象模型,是W3C組織推薦的處理可擴展標記語言(HTML和XMI)的標準編程接口。
W3C已經定義了一系列的DOM接口,通過這些DOM接口可以改變網頁的內容、結構和樣式。
2.DOM樹
文檔:一個頁面就是一個文檔,DOM中使用document表示。
元素:頁面中的所有標籤都是元素,DOM中使用element表示。
節點:頁面中的所有內容都是節點(標籤、屬性、文本、註釋等),DOM中使用node表示
DOM把以上內容都看作是對象
二、獲取元素
1.如何獲取頁面元素
獲取頁面中的元素可以使用以下幾種方式:
a.根據ID獲取
使用getElementById()方法可以獲取帶有ID的元素對象。
<body>
<div id="timer">2019-9-9</div>
<script>
//1.文檔從上往下加載,js寫在下面
//2.get獲得element元素by通過 駝峯命名法
//3.參數 id 區分大小寫
//4.返回的是一個元素對象
var timer = document.getElementById("timer");
console.log(timer);
console.log(typeof timer);
//5.console.dir 打印我們返回的元素對象 更好的查看裏面屬性和方法
console.dir(timer);
</script>
</body>
b.根據標籤名獲取
getElementsByTagName()方法可以返回帶有指定標籤名的對象的集合
<body>
<ul>
<li>知否知否,應是等你好久!1</li>
<li>知否知否,應是等你好久!2</li>
<li>知否知否,應是等你好久!3</li>
<li>知否知否,應是等你好久!4</li>
<li>知否知否,應是等你好久!5</li>
</ul>
<ul id = "nav">
<li>生僻字</li>
<li>生僻字</li>
<li>生僻字</li>
<li>生僻字</li>
<li>生僻字</li>
</ul>
<script>
//1.返回的是獲取過來元素對象的集合 以僞數組形式存儲
var lis = document.getElementsByTagName("li");
console.log(lis);
console.log(lis[0]);
//2.我們想要依次打印裏面的元素對象我們可以採取遍歷的方式
for(var i = 0; i <lis.length; i++){
console.log(lis[i]);
}
//3.element.getElementsByTagName() 可以得到這個元素裏面的某些
var nav = document.getElementById('nav');
var navLis = nav.getElementsByTagName('li');
console.log(navLis);
</script>
</body>
注意:
(1)因爲得到的是一個對象的集合,所以我們操作裏面元素就需要遍歷。
(2)得到元素對象是動態的
c.通過HTML5新增的方法獲取
1.getElementsByClassName(‘類名’);根據類名返回元素對象集合。
2.document.querySelector(‘選擇器’);根據指定選擇器返回第一個元素對象。
3.document.querySelectorAll(‘選擇器’);根據指定選擇器返回。
<body>
<div class="box">盒子</div>
<div class="box">盒子</div>
<div id="nav">
<ul>
<li>首頁</li>
<li>產品</li>
</ul>
</div>
<script>
//1.getElementsByClassName 根據類名獲得某些元素的1集合
var boxs = document.getElementsByClassName('box');
console.log(boxs);
//2.querySelector 返回指定選擇器的第一個元素對象 切記裏面的選擇器要加符號 .box #nav
var firstBox = document.querySelector('.box');
console.log(firstBox);
var nav = document.querySelector('#nav');
console.log(nav);
var li = document.querySelector('li');
console.log(li);
//3.querySelectorAll() 返回指定選擇器的所有元素對象集合
var allBox = document.querySelectorAll('.box');
console.log(allBox);
var lis = document.querySelectorAll('li');
console.log(lis);
</script>
</body>
d.特殊元素獲取
獲取body元素
document.body;
獲取html元素
document.documentElement;
<body>
<script>
//1.獲取body元素
var bodyEle = document.body;
console.log(bodyEle);
console.dir(bodyEle);
//2.獲取html元素
var htmlEle = document.documentElement;
console.log(htmlEle);
</script>
</body>
三、事件基礎
1.事件概述
JavaScript使我們有能力創建動態頁面,而事件是可以被JavaScript偵測到的行爲。
簡單理解:觸發——響應機制。
網頁中的每個元素都可以產生某些可以觸發JavaScript的事件,例如,我們可以在用戶點擊某按鈕時產生一個事件,然後去執行某些操作。
2.執行事件步驟
(1)獲取事件源
(2)註冊事件(綁定事件)
(3)添加事件處理機制(採取函數賦值形式)
3.常見的鼠標事件
四、操作元素
1.DOM操作可以改變網頁內容、結構和樣式,我們可以利用DOM元素來改變元素裏面的內容、屬性等。
2.改變元素內容
element.innerText
從起始到終止位置的內容,但它去除html標籤,同時空格和換行也會去掉;
element.innerHTML
起始位置到終止位置的全部內容,包括html標籤,同時保留空格和換行。
<body>
<button id="dyz">第一張</button>
<button id="dez">第二張</button><br>
<img src='beauty_20200313143156.jpg' title="這是第一張圖片">
<script>
//修改元素屬性
//1.獲取元素
var dyz = document.getElementById('dyz');
var dez = document.getElementById('dez');
var img = document.querySelector('img');
//2.註冊事件 處理程序
dez.onclick = function(){
img.src = "beauty_20200313143213.jpg";
img.title = "這是第二張圖片";
}
dyz.onclick = function(){
img.src = "beauty_20200313143156.jpg";
img.title = "這是第一張圖片";
}
</script>
</body>
<body>
<img src="beauty_20200313143156.jpg">
<div>上午好</div>
<script>
//根據系統時間不同來判斷,所以需要用到日期內置對象
//利用多分支語句來設置不同圖片
//需要一個圖片,並且根據時間修改圖片,就需要用到操作元素src屬性
//需要一個div元素,顯示不同的時間問候語,修改元素內容即可
//1.獲取元素
var img = document.querySelector('img');
var div = document.querySelector('div');
//2.得到當前的小時數
var date = new Date();
var h = date.getHours();
//3.判斷小時數改變圖片和文字信息
if(h < 12){
img.src = "beauty_20200313143156.jpg";
div.innerHTML = '親,上午好,好好寫代碼';
} else if(h < 18){
img.src = "beauty_20200313143213.jpg";
div.innerHTML = '親,下午好,好好寫代碼';
}else {
img.src = "IMG_20190930_204918.jpg";
div.innerHTML = '親,晚上好,好好寫代碼';
}
</script>
</body>
3.表單元素的屬性操作
利用DOM可以操作如下表單元素的屬性:
type、 value、 checked、 selected、 disabled、
<body>
<button>按鈕</button>
<input type="text" name="" value="輸入內容">
<script>
//1.獲取元素
var btn = document.querySelector('button');
var input = document.querySelector('input');
//2.註冊事件 處理程序
btn.onclick = function(){
//input.innerHTML = '點擊了';這個是普通盒子 比如 div 標籤裏面的內容
//表單裏面的值 文字內容是通過value來修改的
input.value = '被點擊了';
//如果想要某個表單被禁用 不能再點擊 disabled 我們想要這個按鈕 button禁用
// btn.disabled = true;
this.disabled = true;
//this 指向的是事件函數的調用者 btn
}
</script>
</body>
密碼框案例:
<head>
<meta charset="utf-8">
<title></title>
<style>
.box{
position: relative;
width: 400px;
border-bottom: 1px solid #ccc;
margin: 100px auto;
}
.box input{
width: 370px;
height: 30px;
border: 0;
outline: none;
}
.box img{
position: absolute;
top: 2px;
right: 2px;
width: 24px;
}
</style>
</head>
<body>
<div class="box">
<label form="">
<img src="close.png" id="eye">
</label>
<input type="password" name="" id="pwd">
</div>
<script>
//1.獲取元素
var eye = document.getElementById('eye');
var psw = document.getElementById('pwd');
//2.註冊事件 處理程序
var flag = 0;
eye.onclick = function(){
if(flag == 0){
pwd.type = 'text';
flag = 1; //賦值操作
eye.src = 'open.png';
}else {
pwd.type = 'password';
flag = 0;
eye.src = 'close.png';
}
}
</script>
</body>
4.樣式屬性操作
我們可以通過JS修改元素大小、顏色、位置等樣式。
1.element.style 行內樣式
2.element.className 類樣式操作
注意:(1)JS裏面的樣式採取駝峯命名法,比如:fontSize、backgroundColor; (2)JS修改style樣式操作,產生的是行內樣式,css權重比較高
<style>
div {
width: 200px;
height: 200px;
background-color: pink;
}
</style>
</head>
<body>
<div></div>
<script>
//1.獲取元素
var div = document.querySelector('div');
//2.註冊事件 處理程序
div.onclick = function(){
//div.style裏面的屬性 採取駝峯命名法
this.style.backgroundColor = 'purple';
this.style.width = '250px';
}
</script>
</body>
<style>
.box{
position: relative;
width: 74px;
height: 88px;
border: 1px solid #ccc;
margin: 100px auto;
font-size: 12px;
text-align: center;
color: #f40;
}
.box img{
width: 60px;
margin-top: 5px;
}
.close-btn{
position: absolute;
top: -1px;
left: -16px;
width: 14px;
height: 14px;
border: 1px solid #ccc;
line-height: 14px;
font-family: Arial, Helvetica,sana-serif;
cursor: pointer;
}
</style>
</head>
<body>
<div class="box">
淘寶二維碼
<img src="code.png">
<i class="close-btn">x</i>
</div>
<script>
//1.獲取元素
var btn = document.querySelector('.close-btn');
var box = document.querySelector('.box');
//2.註冊事件 處理程序
btn.onclick = function(){
box.style.display = 'none';
}
</script>
</body>
<style>
input{
color: #999;
}
</style>
</head>
<body>
<input type="text" name="" value="手機">
<script>
//1.獲取元素
var text = document.querySelector('input');
//2.註冊事件 獲得焦點事件 onfocus
text.onfocus = function(){
// console.log('得到了焦點');
if(this.value === '手機'){
this.value = '';
}
//獲得焦點 需要把文本框中的文字變黑
this.style.color = '#333';
}
//3.註冊事件 失去焦點事件 onblur
text.onblur = function(){
// console.log('失去了焦點');
if(this.value === ''){
this.value = '手機';
}
//失去焦點 顏色變淺
this.style.color = '#999';
}
</script>
</body>
<style>
div{
width: 150px;
height: 150px;
background-color: pink;
}
.change{
background-color: purple;
color: #fff;
font-size: 25px;
margin-top: 100px;
}
</style>
</head>
<body>
<div>文本</div>
<script>
//1.使用element.style獲得修改元素樣式 如果樣式比較少 或者功能簡單的情況下使用
var test = document.querySelector('div');
test.onclick = function(){
// this.style.backgroundColor = 'purple';
// this.style.color = '#fff';
// this.style.fontSize = '25px';
// this.style.marginTop = '100px';
//讓我們當前元素的類名等於 change
//2.我們可以通過修改元素 的className更改元素的樣式 適用於樣式較多或者功能更復雜的情況
this.className = 'change';
}
</script>
</body>
注意:
(1)如果樣式修改較多,可以採取操作類名方式更改元素樣式;
(2)class因爲是保留字,因此使用className來操作元素類名屬性;
(3)className會直接更改元素的類名,會覆蓋原先的類名。
5.自定義屬性的操作
(1)獲取屬性值
element.屬性; (獲取屬性值)
element.getAttribute(‘屬性’) ;
區別:
element.屬性; 獲取內置屬性值(元素本身自帶的屬性)
element.getAttribute(‘屬性’); 主要獲得自定義的屬性(標準)我們程序員自定義的屬性
(2)設置屬性值
element.屬性 = ‘值’; 設置內置屬性
element.setAttribute(‘屬性’,‘值’);
(3)移除屬性
element.removeAttribute(‘屬性’);
6.H5自定義屬性
自定義屬性的目的:是爲了保存並使用數據,有些數據可以保存到頁面中而不用保存到數據庫中。
自定義屬性獲得通過getAttribute(‘屬性’)獲取;但是有些自定義屬性很容易引起歧義,不容易判斷是元素的內置屬性還是自定義屬性。H5給我們新增了自定義屬性:
(1)設置H5自定義屬性
H5規定自定義屬性data-開頭:
比如:
<div data-index = "1"></div>
或者使用JS設置
element.setAttribute('data-index', 2);
(2)獲取H5自定義屬性
1.兼容性獲取:element.getAttribute(‘data-index’)
2.H5新增element.dataset.index 或者
element.dataset[‘index’] ie11以上
<body>
<div getTime = "20" data-index = "2" data-list-name = "andy"></div>
<script>
var div = document.querySelector('div');
console.log(div.getAttribute("getTime"));
div.setAttribute('data-time', 20);
console.log(div.getAttribute('data-index'));
console.log(div.getAttribute('data-list-name'));
//h5新增 他只能獲取data- 開頭的
//dataset是一個集合,裏面存放了所有以data開頭的自定義屬性
console.log(div.dataset);
console.log(div.dataset.index);
//如果自定義屬性裏面有多個-連接的單詞,我們獲取的時候採取 駝峯命名法
console.log(div.dataset.listName);
</script>
</body>
7.節點操作
a.獲取元素通常使用兩種方式:
(1)利用DOM提供的方法獲取元素
document.getElementById()
document.getElementsByTagName()
document.querySelector()等,
缺點:繁瑣、沒有邏輯性
(2)利用節點層級關係獲取元素
利用父子兄弟節點關係獲取元素
邏輯性強,但是兼容性稍差
b.節點概述
一般地,節點至少擁有nodeType(節點類型)、nodeName(節點名稱)和nodeValue(節點值)這三個基本屬性。
元素節點nodeType爲1
屬性節點nodeType爲2
文本節點nodeType爲3(文本節點包含文字、空格、換行符)
實際開發中,節點操作主要操作的是元素節點
c.節點層級
常見的是父子兄層級關係
(1)父級節點
node.parentNode
(2)子節點
parentNode.childNodes(標準):拿到的是所有子節點, 包含元素節點 文本節點等等;實際開發中不提倡
parentNode.children(非標準):但是得到了各個瀏覽器的支持,因此可以放心使用
parentNode.firstChild:firstChild返回第一個子節點,找不到則返回null,同樣,也是包含所有節點
parentNode.lastChild:返回最後一個子節點,找不到則返回null,同樣,也是包含所有節點
parentNode.firstElementChild和parentNode.lastElementChild都返回的是元素節點,找不到則返回null, 這兩個方法都有兼容性問題,IE9以上才支持。
<body>
<ol>
<li>我是li1</li>
<li>我是li2</li>
<li>我是li3</li>
<li>我是li4</li>
</ol>
<script>
var ol = document.querySelector('ol');
//1.fistChild 獲取的是第一個子節點 不管是文本節點還是元素節點
console.log(ol.firstChild);
console.log(ol.lastChild);
//2.firstElementChild 返回第一個元素節點
console.log(ol.firstElementChild);
console.log(ol.lastElementChild);
//3.實際開發的寫法,既沒有兼容性問題又返回第一個子元素
console.log(ol.children[0]);
console.log(ol.children[ol.children.length - 1]);
</script>
</body>
(3)兄弟節點
node.nextSibling: 返回當前元素的下一個兄弟節點,找不到返回Null,同樣包含所有節點
node.prexiousSibling:返回當前元素的上一個兄弟節點,找不到返回Null,同樣包含所有節點
node.nextElementSibling: 返回當前元素的下一個兄弟元素節點,找不到返回Null
node.prexiousElementSibling:返回當前元素的上一個兄弟節點,找不到返回Null
node.nextElementSibling和node.prexiousElementSibling都存在兼容性問題,IE9以上才支持
<body>
<div>我是div</div>
<span>我是span</span>
<script>
var div = document.querySelector('div');
//1.nextSibling 下一個兄弟節點 包含元素節點和文本節點
console.log(div.nextSibling);
console.log(div.previousSibling);
//2.nextElementSibling 得到下一個兄弟節點
console.log(div.nextElementSibling);
console.log(div.previousElementSibling);
</script>
</body>
解決方法:封裝一個兼容性的函數;
function getNextElementSibling(element) {
var el = element;
while (el = el.nextElementSibling) {
if (el.nodeType === 1) {
return el;
}
}
return null;
}
(4)創建節點
document.createElement(‘tagName’)
document.createElement(‘tagName’)方法創建由tagName指定的的HTML元素,因爲這些元素原先不存在,是根據我們的需求動態生成的,所以我們也稱爲動態創建元素節點。
(5)添加節點
node.appendChild(child)
node.appendChild()方法將一個節點添加到指定父節點的子節點列表末尾,類似於css裏面的after僞元素。
<body>
<ul>
<li>123</li>
</ul>
<script>
//1.創建節點
var li = document.createElement('li');
//2.添加節點 node.appendChild(Child) node是父級 child 是子集 後面追加元素 類似於數組的push
var ul = document.querySelector('ul');
ul.appendChild(li);
//3.添加節點 node.insertBefore(child, 指定元素)
var lili = document.createElement('li');
ul.insertBefore(lili, ul.children[0]);
//4.我們先要頁面添加一個新的元素:1.創建元素 2.添加元素
</script>
</body>
簡單留言發佈:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title></title>
<style>
textarea{
width: 100px;
height: 100px;
}
ul li{
background-color: pink;
width: 300px;
margin-top: 5px;
}
</style>
</head>
<body>
<textarea name="" id=""></textarea>
<button>發佈</button>
<ul>
</ul>
<script>
//1.獲取元素
var btn = document.querySelector('button');
var text = document.querySelector('textarea');
var ul = document.querySelector('ul');
//2.註冊事件
btn.onclick = function(){
if(text.value == ''){
alert('你沒有輸入內容!!!')
return false;
}else{
// console.log(text.value);
//(1)創建元素
var li = document.createElement('li');
//先有 li 才能賦值
li.innerHTML = text.value;
//(2)添加元素
ul.insertBefore(li,ul.children[0]);
}
}
</script>
</body>
</html>
效果圖:
(6)刪除節點
node.removeChild(child)
node.removeChild()方法從DOM中刪除一個子節點,返回刪除的節點。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<button>刪除</button>
<ul>
<li>熊大</li>
<li>熊二</li>
<li>光頭強</li>
</ul>
</body>
<script>
//1.獲取元素
var ul = document.querySelector('ul');
var btn = document.querySelector('button');
//2.刪除元素
// ul.removeChild(ul.children[0]);
//3.點擊按鈕依次刪除裏面的子節點
btn.onclick = function() {
if (ul.children.length == 0) {
this.disabled = true;
} else {
ul.removeChild(ul.children[0]);
}
}
</script>
</html>
(6)複製節點(克隆節點)
node.cloneNode()
node.cloneNode()方法返回調用該方法的節點的一個副本,也稱爲克隆節點/拷貝節點
注意:
1.如果括號裏面參數爲空或者false,則是淺拷貝,即只是克隆複製節點本身,不克隆裏面的子節點(內容)。
2.如果括號裏面爲true,則是深拷貝,會複製節點本身及其裏面的所有子節點
動態創建刪除表格案例:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<style>
table {
width: 500px;
margin: 100px auto;
border-collapse: collapse;
text-align: center;
}
td,
th {
border: 1px solid #333;
}
thead tr {
height: 40px;
background-color: #ccc;
}
</style>
</head>
<body>
<table cellspacing="0">
<thead>
<tr>
<th>姓名</th>
<th>科目</th>
<th>成績</th>
<th>操作</th>
</tr>
</thead>
<tbody>
</tbody>
</table>
<script>
//1.準備數據
var datas = [{
name: '張三',
subject: 'javascript',
score: 100
}, {
name: '李四',
subject: 'javascript',
score: 90
}, {
name: '王五',
subject: 'javascript',
score: 95
}, {
name: '王七',
subject: 'javascript',
score: 89
}];
//2.tbody中創建行:有幾個人就創建幾行,通過數組長度得到
var tbody = document.querySelector('tbody');
for (var i = 0; i < datas.length; i++) { //外面的for循環管行數
//創建行
var tr = document.createElement('tr');
tbody.appendChild(tr);
//行裏面創建單元格 td 單元格數量取決於每個對象裏面的屬性個數
//for循環遍歷對象
for (var k in datas[i]) { //裏面的單元格管列數
var td = document.createElement('td');
//把對象裏面的屬性值給 td
console.log(datas[i][k]);
td.innerHTML = datas[i][k];
tr.appendChild(td);
}
//3.創建有刪除2個字的單元格
var td = document.createElement('td');
td.innerHTML = '<a href = "javascript:;">刪除</a>';
tr.appendChild(td);
}
//4.刪除操作
var as = document.querySelectorAll('a');
for (var i = 0; i < as.length; i++) {
as[i].onclick = function() {
//點擊a 刪除當前a所在的行 node.removeChild(child)
tbody.removeChild(this.parentNode.parentNode);
}
}
</script>
</body>
</html>
五、三種動態創建元素的區別
- documen.write()
- document.innerHTML
- document.createElement()
區別:
1.document.write是直接將內容寫入頁面流,但是文檔流執行完畢,則它會導致頁面重繪
2.innerHTML是將內容寫入某個DOM節點,不會導致頁面全部重繪
3.innerHTML創建多個元素效率更高(不要拼接字符串,採取數組形式拼接),結構稍微復
4.createElement()創建多個元素效率稍低一點點,但是結構清晰。