JavaScript?DOM?API的使用教程及綜合案例
一. 什么是DOM
JavaScript主要由ECMAScript, DOM, BOM這三部分組成; 我們要知道要完成一個程序, 光有語法是遠(yuǎn)遠(yuǎn)不夠的, 對于JS來說, 除JS語法(ES)外, 還需要掌握一些WebAPI, 這些API是瀏覽器給JS代碼提供的功能, 即DOM和BOM; DOM是頁面文檔對象模型, 可以對頁面中的元素進(jìn)行操作, 而BOM是瀏覽器對象模型, 可以對瀏覽器窗口進(jìn)行操作; 本篇博客中主要介紹的就是DOM.
DOM 全稱為 Document Object Model, 是頁面文檔對象模型, html中的每個標(biāo)簽都是可以映射到JS中的一個對象中的, 標(biāo)簽中的內(nèi)容都可以通過JS對象感知到, JS對象修改對應(yīng)的屬性能夠影響到標(biāo)簽的展示, 通過這樣的DOM API就可以讓JS代碼來操作頁面元素.
二. 最常用的DOM API
1. 選中頁面元素
在DOM中, 任何一個頁面, 都會有一個document對象, 是頁面的一個全局對象, 所有的DOM API都是通過document對象類展開的, 其中document對象中的querySelector和querySelectorAll函數(shù)可以用來選擇元素, 通過傳入CSS選擇器來達(dá)到目的, 選擇的范圍是位于該函數(shù)之前所存在的選擇器, 沒找到返回值為null.
let obj = document.querySelector('選擇器');

要注意使用querySelector函數(shù)如果符合選擇的標(biāo)簽在頁面中有多個, 就只會選擇在頁面中第一次出現(xiàn)的標(biāo)簽.

如果想把符合選擇的元素都選中就需要使用querySelectorAll函數(shù)了, 在使用上和和querySelector 是一樣的.
let elem = document.querySelectorAll('選擇器');使用該函數(shù)會返回一個類似于數(shù)組的對象, 用法和數(shù)組相同.

將得到的數(shù)組對象里面的元素展開查看, 會發(fā)現(xiàn)有很多的屬性, 這些屬性都是DOM原生的一些屬性.

2. 操作元素的屬性
2.1 事件概念
JS要構(gòu)建動態(tài)頁面, 就需要感知到用戶的行為, 而 “事件” 就是針對用戶的操作進(jìn)行的一些響應(yīng), 比如鼠標(biāo)點擊, 鼠標(biāo)移動, 鍵盤輸入, 調(diào)整瀏覽器窗口這些都是用戶的操作, 而代碼就需要根據(jù)這些事件做出相應(yīng)的響應(yīng).
事件的三要素:
- 事件源, 哪個HTML元素產(chǎn)生的事件.
- 事件類型, 比如鼠標(biāo)點擊, 鼠標(biāo)移動, 鍵盤輸入等.
- 事件處理程序, 當(dāng)事件發(fā)生之后, 要執(zhí)行哪個代碼.
前端頁面中, 針對不同的事件也是有不同的處理方式的, 而處理方式都是再最開始的時候就設(shè)定好的(事件綁定).
看下面的這一行代碼就是直接在元素標(biāo)簽中使用onXXX這樣的屬性來綁定一個事件處理程序, onclick是一個描述處理鼠標(biāo)點擊的事件.
<button onclick="alert('hello')">點一下試試</button>
如果事件處理的代碼比較多的話使用上面這種寫法就不太合適了, 所以更推薦的是下面這種寫法, 可以直接使用onXXX這樣的方法進(jìn)行綁定, 效果和上面是一樣的.
<script !src="">
let button = document.querySelector("button");
button.onclick = function (){
alert("hello");
}
</script>
<button onclick="alert('hello')">點一下試試</button>
當(dāng)然,這里的JS代碼如果是寫在一個單獨的JS文件中就更好了, 但本篇中的示范代碼都比較簡單, 就使用內(nèi)嵌式的寫法來引入JS代碼了.
2.2 獲取/修改元素內(nèi)容
在選中元素后, 就可以使用innerHTML屬性來獲取/修改一個標(biāo)簽里面的內(nèi)容了.
//1.選中標(biāo)簽 let var_name = document.querySelector(); //2.獲取內(nèi)容 let content = var_name.innnerHTML; //3.修改內(nèi)容 var_name.innerHTML = '修改值';
代碼示例, 將點擊按鈕和輸出div中的內(nèi)容綁定.
<div> hello world</div>
<button>點一下試試</button>-->
<script>
let but = document.querySelector('but');
but.onclick = function () {
let div = document.querySelector('div');
console.log(div.innerHTML);
}
</script>

觀察控制臺的結(jié)果, 控制臺中多次點擊按鈕的結(jié)果都被折疊輸出了, 這是因為chrome控制臺會默認(rèn)把相鄰且相同的日志進(jìn)行合并, 另外再顯示一個數(shù)字表示輸出的次數(shù), 我們可以點擊開發(fā)者工具的設(shè)置欄, 設(shè)置一下讓它不合并就行了.

還要注意的是, 通過innerHTML是可以獲取到div內(nèi)部的html結(jié)構(gòu)的, 比如下面的的代碼, 會將div標(biāo)簽中的html代碼也獲取到, 而innerText只能獲取文本內(nèi)容, 并不能獲取html結(jié)構(gòu), innerHTML用的場景是要比innerText更多的.
<div>
<span>hello world</span>
<span>hello world</span>
</div>
<button class="but">點一下試試</button>
<script>
let but = document.querySelector('.but');
but.onclick = function () {
let div = document.querySelector('div');
console.log(div.innerHTML);
}
</script>


修改元素也是一樣的操作, 比如將上面代碼中的div中的內(nèi)容修改為一個標(biāo)題.
<div>
<span>hello world</span>
<span>hello world</span>
</div>
<button class="but">點一下試試</button>
<script>
let but = document.querySelector('.but');
but.onclick = function () {
let div = document.querySelector('div');
div.innerHTML = '<h1>這是一個一級標(biāo)題</h1>>';
console.log(div.innerHTML)
}
</script>

計數(shù)器
有了上面的獲取和修改元素的知識, 我們這里實現(xiàn)一個簡單的計數(shù)器, 就是點擊一下按鈕, 計數(shù)器就+1.
實現(xiàn)思路也很簡單, 用戶的點擊操作, 就會觸發(fā)點擊事件, 就是先獲取到計數(shù)元素中的內(nèi)容, 然后將元素內(nèi)容進(jìn)行加一操作再寫回元素中, 代碼如下:
<div id='count'>0</div>
<button id='countAdd'>計數(shù)器:點擊+1</button>
<script !src="">
let counterAdd = document.querySelector('#countAdd');
counterAdd.onclick = function () {
let num = document.querySelector('#count');
numAdd = parseInt(num.innerHTML) + 1
num.innerHTML = numAdd;
};
</script>

這個代碼要注意的是, num.innerHTML這里拿到的元素內(nèi)容是字符串類型的, 直接進(jìn)行加法運(yùn)算就是字符串拼接的效果了, 而要完成算數(shù)相加的效果就需要將字符串轉(zhuǎn)換為整數(shù), 和Java中類似, 可以使用parseInt方法將字符串轉(zhuǎn)換為整數(shù), 而如果是浮點數(shù)就使用parseFloat方法
2.4 獲取/修改元素屬性
點擊圖片切換
上面介紹的是修改元素(標(biāo)簽)中的內(nèi)容, 我們還可以在代碼中使用DOM直接獲取元素的屬性并修改元素的屬性, 比如這里實現(xiàn)一個效果, 就是點擊一個圖片就可以切換到另一張圖片, 然后再點擊就能再切換回來, 這個案例我們只需要設(shè)置點擊事件為修改圖片的路徑即可, 也就是修改src屬性.
代碼如下:
這里要注意圖片的路徑盡量不要設(shè)置成中文的, 中文路徑在瀏覽器中涉及轉(zhuǎn)義重新編碼的問題, 轉(zhuǎn)義后路徑就可能沒有中文字符了, 判斷就可能出問題了.
<style>
img {
height: 500px;
}
</style>
<img src="./man.jpg" alt="">
<script !src>
let img = document.querySelector("img");
console.dir(img);
img.onclick = function() {
if (img.src.indexOf('wo') !== -1) {
img.src = './man.jpg';
} else {
img.src = './woman.jpg';
}
}
</script>

一個標(biāo)簽中具體有哪些屬性可以修改, 可以使用console.dir()函數(shù)來獲取DOM API能夠操作的全部屬性, 比如img元素.

2.5 獲取/修改表單元素屬性
這里把表單元素單拎出來是因為, 是因為, 表單元素中有一些特別的屬性是普通標(biāo)簽沒有的, 主要需要區(qū)別的是一些表單元素想要獲取其中用戶輸入的內(nèi)容的話是不能通過innerHTML拿到的, 這是因為input, textarea… 這些標(biāo)簽元素都是單標(biāo)簽, 是沒有內(nèi)容的, 正確的獲取/修改的方式應(yīng)該是通過這些標(biāo)簽的value屬性來進(jìn)行.
表單計數(shù)器
比如input標(biāo)簽, 還是在文本框中實現(xiàn)一下計數(shù)功能, 同樣的要注意拿到的value屬性的值也是字符串類型的, 要注意進(jìn)行類型轉(zhuǎn)換.
<input type="text" value="0" id='count'>
<button id='countAdd'>計數(shù)器: 點擊+1</button>
<script !src="">
let counterAdd = document.querySelector('#countAdd');
counterAdd.onclick = function () {
let num = document.querySelector('#count');
numAdd = parseInt(num.value) + 1
num.value = numAdd;
};
</script>

再舉例一個比較常見的場景, 我們平常見的登錄功能中密碼框中的文本可以選擇是否顯示密碼, 這個實現(xiàn)起來其實也很簡單, 通過DOM來修改type屬性的值即可.
<input type="text" id="pw">
<button>隱藏密碼</button>
<script !src="">
let pw = document.querySelector('#pw');
let button = document.querySelector('button');
button.onclick = function() {
if (pw.type == 'text') {
pw.type = 'password';
button.innerHTML = '顯示密碼';
} else {
pw.type = 'text';
button.innerHTML = '隱藏密碼';
}
}
</script>

全選/取消全選按鈕
這里再實現(xiàn)一下全選功能, 也就是有若干個復(fù)選框, 點擊全選按鈕, 就會選中所有的選項, 但只要某個選項取消, 則自動取消全選按鈕的勾選狀態(tài).
實現(xiàn)的基本思路如下:
- 獲取全選按鈕元素, 獲取其按鈕元素
- 注冊全選按鈕的點擊事件, 點擊全選按鈕時, 全選按鈕的checked屬性發(fā)生改變, 將checked屬性值賦值給其他按鈕的checked屬性即完成了全選.
- 對每一個其他復(fù)選按鈕設(shè)置點擊事件, 并將狀態(tài)與全選按鈕關(guān)聯(lián), 即檢查其他復(fù)選按鈕是否選中, 如果選中, 則全選按鈕也選中(修改checked值為true), 否則全選按鈕不選中(修改checked值為false).
- 每次點擊其他框都要檢測其他框是否都選中, 以確定全選按鈕的狀態(tài).
<input type="checkbox" id="all">我全都要 <br>
<input type="checkbox" class="girl">貂蟬 <br>
<input type="checkbox" class="girl">小喬 <br>
<input type="checkbox" class="girl">安琪拉 <br>
<input type="checkbox" class="girl">妲己 <br>
<script>
//checked屬性為checked/true表示選中狀態(tài),為空字符串/false表示未選中
//獲取到元素
let all = document.querySelector('#all');
let girls = document.querySelectorAll('.girl');
//給all注冊點擊事件,選中/取消所有選項
all.onclick = function () {
for (let i = 0; i < girls.length; i++) {
//使girl元素狀態(tài)與all相同
girls[i].checked = all.checked;
}
}
//給所有g(shù)irl元素注冊點擊事件
for (let i = 0; i < girls.length; i++) {
girls[i].onclick = function () {
//檢測當(dāng)前是不是所有的girl元素都被選中了,確定all的狀態(tài)
all.checked = checkGirls(girls);
}
}
//實現(xiàn)checkGirls,檢測當(dāng)前是不是所有的girl元素都被選中了
function checkGirls(girls) {
for (let i = 0; i < girls.length; i++) {
if (!girls[i].checked) {
//只要一個 girl 沒被選中,就認(rèn)為結(jié)果是 false(找到了反例)
return false;
}
}
// 所有 girl 中都沒找到反例, 結(jié)果就是全選中
return true;
}
</script>

2.6 獲取修改樣式屬性
第一種方式是通過修改元素的內(nèi)聯(lián)樣式, 即修改元素的style屬性的值來指定樣式, 這種方式的優(yōu)先級很高, 適用于該樣式比較少的情況.
點擊文字放大
文字放大效果的實現(xiàn), 我們可以給文本所在的標(biāo)簽注冊一個點擊事件, 每點擊一次就將字體大小增大, 即修改CSS的font-size屬性; 思路很簡單, 但JS代碼的寫法上有一些細(xì)節(jié)需要注意, 在CSS中是不區(qū)分大小寫的, 且在CSS中不需要進(jìn)行算數(shù)運(yùn)算, 屬性和變量名是采用的是脊柱式命名法, 但-在JS中就不能用于命名了, 所以JS中采用駝峰命名的形式來表示CSS的屬性, 比如font-size屬性在對應(yīng)JS的中就為fontSize了.
<div style="font-size:20px;">
這是一段文本,點擊之后字體放大
</div>
<script !src="">
let div = document.querySelector("div");
div.onclick = function() {
//1.獲取文字大小屬性
let size = parseInt(div.style.fontSize);
console.log("修改前" + size);
//2.修改文字大小
size += 5;
//3.寫回到屬性
div.style.fontSize = size + "px";
console.log("修改后" + size);
}
</script>

還有一種修改樣式的方式可以通過修改類屬性來達(dá)到修改樣式的效果, 可以通過元素.className來獲取/修改類屬性的值, 由于class是 JS 的保留字, 所以這里獲取類屬性的名字叫做className.
實現(xiàn)夜間/日間模式的切換
實現(xiàn)點擊界面, 切換日間模式和夜間模式
<div class="container light">
這是一大段話. <br>
這是一大段話. <br>
這是一大段話. <br>
這是一大段話. <br>
</div>
<style>
* {
margin: 0;
padding: 0;
}
html, body {
width: 100%;
height: 100%;
}
.container {
width: 100%;
height: 100%;
}
.light {
background-color: #f3f3f3;
color: #333;
}
.dark {
background-color: #333;
color: #f3f3f3;
}
</style>
<script !src="">
let div = document.querySelector('div');
div.onclick = function () {
console.log(div.className);
if (div.className.indexOf('light') != -1) {
div.className = 'container dark';
} else {
div.className = 'container light';
}
}
</script>

3. 操作頁面節(jié)點
上述涉及的操作都是針對頁面已有的元素進(jìn)行操作的, 利用DOM API還可以完成添加/刪除元素的操作.
3.1 新增節(jié)點
添加元素主要有兩個步驟, 首先需要創(chuàng)建一個新的創(chuàng)建元素節(jié)點, 然后把這個元素節(jié)點插入到父元素中就能完成元素的的添加(依賴于DOM樹).
可以使用creatElement方法來創(chuàng)建一個新的元素:
let element = document.createElement('元素標(biāo)簽名');插入到DOM樹中:
父元素.appendChild(創(chuàng)建的子元素);
代碼示例:

關(guān)于插入節(jié)點還可以使用insertBefore將節(jié)點插入到指定節(jié)點之前.
新插入節(jié)點的父元素.insertBefore(新插入的元素, 指定節(jié)點(將要插在這個節(jié)點之前));
<div class="container">
<div>11</div>
<div>22</div>
<div>33</div>
<div>44</div>
</div>
<script>
var newDiv = document.createElement('div');
newDiv.innerHTML = '我是新的節(jié)點';
var container = document.querySelector('.container');
console.log(container.children);
//children可以返回父元素所有的直系子節(jié)點的集合
container.insertBefore(newDiv, container.children[0]);
</script>

3.2 刪除節(jié)點
刪除節(jié)點操作就很簡單了, 語法如下:
父元素.removeChild(需要刪除的子元素);
代碼示例, 比如刪除上面代碼無序列表中的33這個元素.

三. 綜合案例
1. 猜數(shù)字
目標(biāo)頁面如下, 系統(tǒng)可以自動生成[1, 100]之間的隨機(jī)數(shù), 用戶輸入猜測數(shù)字, 能夠提示用戶數(shù)字是猜大了還是猜小了.

這里的邏輯很簡單就不做過多的贅述了, 最關(guān)鍵的是JS中隨機(jī)數(shù)的獲取, 我們可以通過Math.random()函數(shù)來獲取隨機(jī)數(shù), 該函數(shù)生成隨機(jī)數(shù)的范圍是[0,1)區(qū)間內(nèi)的一個小數(shù), 我們需要的是[1,100]之間的整數(shù), 我們可以乘上100后再拿到整數(shù)部分+1就能得到目標(biāo)區(qū)間的數(shù)了.
<button id="flash">重開一局</button>
<div>請輸入要猜的數(shù)字</div>
<input type="text">
<button id="submit">提交</button>
<!--使用這個div來顯示猜測結(jié)果-->
<div class="result"></div>
<script>
//1.生成一個1-100隨機(jī)的整數(shù)
let toGuess = parseInt(100 * Math.random()) + 1;
console.log(toGuess);//用于測試,方便查看猜測結(jié)果
//2.進(jìn)行猜數(shù)字操作,比較用戶輸入的數(shù)和生成的隨機(jī)數(shù)
let input = document.querySelector('input');
let resultDiv = document.querySelector('.result');
let submit = document.querySelector('#submit');
submit.onclick = function() {
//取出輸入框中的內(nèi)容
if (input.value == '') {
//輸入框沒有值,用戶啥都沒輸入,直接返回
return;
}
let inputNum = parseInt(input.value);
//比較大小關(guān)系
if (inputNum < toGuess) {
//小了
resultDiv.innerHTML = '猜小了';
} else if (inputNum > toGuess) {
//大了
resultDiv.innerHTML = '猜大了';
} else {
//猜對了
resultDiv.innerHTML = '猜對了';
}
}
//3.刷新頁面
let flash = document.querySelector('#flash');
flash.onclick = function() {
location.reload();
}
</script>
實際效果:

2. 表白墻
目標(biāo)頁面如下, 點擊提交, 能夠把用戶輸入的話, 顯示在頁面中, 點擊撤銷, 能夠撤回最后一條顯示在頁面的話.

這個案例也沒有難點, 只是的的揉合東西更多了一些, 前端頁面是通過HTML加上CSS彈性布局實現(xiàn)的, 交互通過JavaScript DOM實現(xiàn).
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>表白墻</title>
<style>
* {
/* 消除瀏覽器的默認(rèn)樣式 */
margin: 0;
padding: 0;
/* 保證盒子不被撐大 */
box-sizing: border-box;
}
.container {
width: 600px;
margin: 20px auto;
}
h1 {
text-align: center;
}
p {
text-align: center;
color: #666;
margin: 20px 0;
}
.row {
/* 開啟彈性布局 */
display: flex;
height: 40px;
/* 水平方向居中 */
justify-content: center;
/* 垂直方向居中 */
align-items: center;
}
.row span {
width: 80px;
}
.row input {
width: 200px;
height: 30px;
}
.row button {
width: 280px;
height: 30px;
color: white;
background-color: orange;
/* 去掉邊框 */
border: none;
border-radius: 5px;
}
/* 點擊的時候有個反饋 */
.row button:active {
background-color: grey;
}
</style>
</head>
<body>
<div class="container">
<h1>表白墻</h1>
<p>輸入內(nèi)容后點擊提交, 信息會顯示到下方表格中</p>
<div class="row">
<span>是誰: </span>
<input type="text">
</div>
<div class="row">
<span>對誰: </span>
<input type="text">
</div>
<div class="row">
<span>說: </span>
<input type="text">
</div>
<div class="row">
<button id="submit">提交</button>
</div>
<div class="row">
<button id="revert">撤銷</button>
</div>
<!-- <div class="row">
xxx 對 xx 說 xxxx
</div> -->
</div>
<script>
// 實現(xiàn)提交操作. 點擊提交按鈕, 就能夠把用戶輸入的內(nèi)容提交到頁面上顯示.
// 點擊的時候, 獲取到三個輸入框中的文本內(nèi)容
// 創(chuàng)建一個新的 div.row 把內(nèi)容構(gòu)造到這個 div 中即可.
let containerDiv = document.querySelector('.container');
let inputs = document.querySelectorAll('input');
let button = document.querySelector('#submit');
button.onclick = function() {
// 1. 獲取到三個輸入框的內(nèi)容
let from = inputs[0].value;
let to = inputs[1].value;
let msg = inputs[2].value;
if (from == '' || to == '' || msg == '') {
return;
}
// 2. 構(gòu)造新 div
let rowDiv = document.createElement('div');
rowDiv.className = 'row message';
rowDiv.innerHTML = from + ' 對 ' + to + ' 說: ' + msg;
containerDiv.appendChild(rowDiv);
// 3. 清空之前的輸入框內(nèi)容
for (let input of inputs) {
input.value = '';
}
}
let revertButton = document.querySelector('#revert');
revertButton.onclick = function() {
// 刪除最后一條消息.
// 選中所有的 row, 找出最后一個 row, 然后進(jìn)行刪除
let rows = document.querySelectorAll('.message');
if (rows == null || rows.length == 0) {
return;
}
containerDiv.removeChild(rows[rows.length - 1]);
}
</script>
</body>
</html>
實際效果:

總結(jié)
到此這篇關(guān)于JavaScript DOM API的使用教程及綜合案例的文章就介紹到這了,更多相關(guān)JavaScript DOM API使用內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
微信小程序?qū)崿F(xiàn)簡單手寫簽名組件的方法實例
在使用微信的時候,為方便我們發(fā)送文件可以直接在上面進(jìn)行手寫簽名,這篇文章主要給大家介紹了關(guān)于利用微信小程序?qū)崿F(xiàn)簡單手寫簽名組件的相關(guān)資料,需要的朋友可以參考下2021-07-07

