JavaScript DOM Crash Course JavaScript DOM Crash Course Part - 1 DOM簡介 Document Object Model 由瀏覽器建構的樹的節點(nodes)意味著每個節點都有各自的property跟方法可以運用 JS可以被用來讀寫以及操作DOM 物件導向的呈現方式
作者使用下方這個Item Lister來做為範例教學DOM的操作
這邊的HTML可直接貼上編輯器就可以直接使用
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 <!DOCTYPE html > <html lang ="en" > <head > <meta charset ="UTF-8" > <meta name ="viewport" content ="width=device-width, initial-scale=1.0" > <meta http-equiv ="X-UA-Compatible" content ="ie=edge" > <link rel ="stylesheet" href ="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0-beta/css/bootstrap.min.css" integrity ="sha384-/Y6pD6FV/Vv2HJnA6t+vslU6fwYXjCFtcEpHbNJ0lyAFsXTsjBbfaDjzALeQsN6M" crossorigin ="anonymous" > <title > Item Lister</title > </head > <body > <header id ="main-header" class ="bg-success text-white p-4 mb-3" > <div class ="container" > <div class ="row" > <div class ="col-md-6" > <h1 id ="header-title" > Item Lister</h1 > </div > <div class ="col-md-6 align-self-center" > <input type ="text" class ="form-control" id ="filter" placeholder ="Search Items..." > </div > </div > </div > </header > <div class ="container" > <div id ="main" class ="card card-body" > <h2 class ="title" > Add Items</h2 > <form id ="addForm" class ="form-inline mb-3" > <input type ="text" class ="form-control mr-2" id ="item" > <input type ="submit" class ="btn btn-dark" value ="Submit" > </form > <h2 class ="title" > Items</h2 > <ul id ="items" class ="list-group" > <li class ="list-group-item" > Item 1 <button class ="btn btn-danger btn-sm float-right delete" > X</button > </li > <li class ="list-group-item" > Item 2 <button class ="btn btn-danger btn-sm float-right delete" > X</button > </li > <li class ="list-group-item" > Item 3 <button class ="btn btn-danger btn-sm float-right delete" > X</button > </li > <li class ="list-group-item" > Item 4 <button class ="btn btn-danger btn-sm float-right delete" > X</button > </li > </ul > </div > </div > <script src ="dom.js" > </script > </body > </html >
檢視 document 的物件 console.dir(document);
這邊會在開發者工具印出非常多的properties以及methods不過作者會挑幾個比較重要的說明
1 2 3 4 console .log(document .方法)
document常用方法介紹: 1 2 3 4 5 6 7 8 9 console .log(document .domain);console .log(document .URL);console .log(document .title);console .log(document .doctype);console .log(document .body);console .log(document .head);console .log(document .forms);console .log(document .links);console .log(document .images);
也可以直接修改title
1 2 document .title = '123' ;
下方這個方法會給我們一個HTMLCollection包含了所有的HTML元素以及很多可以使用的方法(methods)
1 console .log(document .all);
如果我們想要擷取其中的內容:
可以這樣使用使用他的檢索號碼就可以抓取內容
1 console .log(document .all[1 ]);
selectors(選取器)介紹 用來抓取元素 getElementById 輸入要選取的 id 就可以抓取選取的元素
1 console .log(document .getElementById('header-title' ));
也可以把抓取的內容指派給變數使用,這樣在呼叫的時候就只要呼叫變數就好不用整串都打
1 2 3 var headerTitle = document .getElementById('header-title' );console .log(headerTitle);
textContent & innerText 這兩個方法可以針對選取的元素修改其文字內容
它們的不同之處在於:
textContent不會看到CSS修改的部分 innerText會看到CSS修改的部分
1 2 3 headerTitle.textContent = 'Hello' ; headerTitle.innerText = 'Goobye' ;
innerHTML 用來加入新的HTML tag來加入舊的tag並不是直接取代
1 headerTitle.innerHTML = '<h3>HEllo</h3>' ;
原本的tag還保留
使用過後修改成'<h3>HEllo</h3>'
style 修飾被抓取元素的CSS
選擇要使用的CSS屬性的部分不能照原本CSS格式的寫法要改成JS的寫法(camel型態的字首英文大小)
1 header.style.borderBottom = 'solid 3px #000' ;
多加了底線上去
getElementByClassName 一樣會用HTMLCollection包裝好內容印出給我們
1 2 3 var items = document .getElementsByClassName('list-group-item' );console .log(items);
印出結果:
這邊我們可以使用console.log(items[1])
擷取內容
並且修改選取的元素文字內容
1 items[1 ].textContent = 'hello2' ;
也可以更改他的CSS
1 2 3 items[1 ].style.fontWeight = 'bold' ; items[1 ].style.backgroundColor = 'yellow' ;
CSS修飾全部選取的內容
使用下面這串是會報錯的
因為它是一個HTMLCollection沒有辦法直接使用方法,所以必須使用迴圈一個一個印出去使用方法
1 2 items.style.backgroundColor = '#f4f4f4' ;
正確解法:
1 2 3 for (i = 0 ; i < items.length; i++) { items[i].style.backgroundColor = 'red' ; }
這樣就可以全部都上色瞜!
getElementByTagName 這邊會的到跟上面getElementByClassName一樣的結果,因為選取的是一樣的元素
1 2 3 4 5 6 7 8 9 10 11 12 13 var li = document .getElementsByTagName('li' );console .log(li);console .log(li[1 ]);li[1 ].textContent = 'hello2' ; li[1 ].style.fontWeight = 'bold' ; li[1 ].style.backgroundColor = 'yellow' ; for (i = 0 ; i < li.length; i++) { li[i].style.backgroundColor = 'red' ; }
這邊的例子可以看到CSS的修飾的部分一樣會吃到item 5因為DOM Seletor這邊抓取的是tag<li>
如果這邊處理的在getElementByClassName的話就不會出現紅色的背景因為item 5 沒有class
querySelector 可以選取任何在HTML上面的元素以及class,id都可以,並做修改跟操作
1 2 3 4 5 6 7 8 var header = document .querySelector('#main-header' );header.style.borderBottom = 'solid 4px red' var input = document .querySelector('input' );input.value = 'Hello World' ; var submit = document .querySelector('input[type ="submit"]' );submit.value = "Send" ;
querySelector - CSS偽類的使用 如果沒有作處理就影響第一個 last-child nth-child(i) 1 2 3 4 5 6 7 8 9 10 var item = document .querySelector('.list-group-item' );item.style.color = 'red' var lastItem = document .querySelector('.list-group-item:last-child' );lastItem.style.color = 'green' ; var secondItem = document .querySelector('.list-group-item:nth-child(2)' );secondItem.style.color = 'coral' ;
querySelectorAll 可以抓取所有選取的內容HTML tags, id, class並且產一個Nodelist它是可以使用array function的!!
1 2 var titles = document .querySelectorAll('.title' );console .log(titles);
1 2 titles[0 ].textContent = 'Hello' ;
選取基數元素上色(進階處理): 一樣使用偽類 nth-child(i)
裝飾元素
1 2 3 4 5 var odd = document .querySelectorAll('li:nth-child(odd)' );for (var i = 0 ; i < odd.length; i++) { odd[i].style.backgroundColor = 'green' }
JavaScript DOM Crash Course Part - 2 DOM的移動(traversing the DOM) parentNode 抓取目前物件的parent也就是外層的物件
1 2 3 4 5 var itemList = document .querySelector('#items' );console .log(itemList.parentNode);itemList.parentNode.style.backgroundColor = 'red'
這邊抓取的是item的id它的parentNode是外層的div
然後我們對它修飾CSS
並且parentNode的使用是可以疊起來的
1 console .log(itemList.parentNode.parentNode.parentNode);
會找的外層的外層的外層找到body去了
parentElement 幾乎跟parentNode的功能一樣是可以互相替換的
1 2 3 console .log(itemList.parentElement);itemList.parentElement.style.backgroundColor = 'red' console .log(itemList.parentElement.parentElement.parentElement);
childNodes(不推薦使用) 1 console .log(itemList.childNodes);
中間包含的text是指斷行
所以當你把它們全都黏在一起時text就會消失 因為中間的斷行消失
children(推薦使用) 功能跟childNodes一樣不過不會顯示出進去斷行 並且呈現方式變成HTMLCollection 1 console .log(itemList.children);
如果想要擷取裡面的內容:
1 console .log(itemList.children[1 ]);
要修改選取元素的CSS:
1 itemList.children[1 ].style.backgroundColor = 'yellow' ;
修改其CSS為背景色黃色
Firstchild(不推薦使用) 會印出第一個元素,但是這個方法一樣會印出斷行所以基本上會印出text
1 console .log(itemList.firstChild);
FirstElementChild(推薦使用) 這個就不會印出text搂
1 console .log(itemList.firstElementChild);
當然也可以針對它選取的元素做文字修改
1 itemList.firstElementChild.textContent = 'hello 1' ;
lastchild(不推薦使用) 跟firstchild相反印出最後一個元素但是缺點是會印出斷行印出text
1 console .log(itemList.firstChild);
LastElementChild(推薦使用) 不會印出斷行text以及也可以進行文字修改操作
1 2 3 console .log(itemList.lastElementChild);itemList.lastElementChild.textContent = 'hello 4' ;
nextSibling(不推薦使用) 會抓取sibling 下一個位於同一層的元素,一樣的缺點會抓取斷行出現text
1 console .log(itemList.nextSibling);
nextElementSibling(推薦使用) 不會出現斷行正常抓取下一個同層元素
1 console .log(itemList.nextElementSibling);
previousSibling(不推薦使用) 會抓取前一個位於同一層的元素 ,一樣的缺點會抓取斷行出現text
1 console .log(itemList.previousSibling);
previousElemntSibling(推薦使用) 不會出現斷行正常抓取上一個同層元素
並且可以進行操作
1 2 console .log(itemList.previousElementSibling);itemList.previousElementSibling.style.color = 'green' ;
createElement 創造新的元素
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 var newDiv = document .createElement('div' );newDiv.className = 'hello' newDiv.id = 'hello1' ; newDiv.setAttribute('title' , 'hello Div' ); var newDivText = document .createTextNode('Hello World' );newDiv.appendChild(newDivText); console .log(newDiv);
印出的結果
把創造出來的div放進去專案中
1 2 3 4 5 var container = document .querySelector('header .container' );var h1 = document .querySelector('header h1' );container.insertBefore(newDiv, h1);
印出結果
修改newDiv 的CSS
1 newDiv.style.fontSize = '30px' ;
JavaScript DOM Crash Course Part - 3 這個部分的主題會環繞著事件(event)
事件監聽 (addEventListener) 新增一個按鍵等下作範例使用
我們可以對這個案件做事件監聽,並且在事件’click’發生的時候跑buttonClick這個function會印出’Button clicked’字樣
1 2 3 4 5 var button = document .getElementById('button' ).addEventListener('click' , buttonClick);function buttonClick ( ) { console .log('Button clicked' ); }
funciton內部的功能也可以改成改寫header-title的文字:
1 2 3 4 5 6 7 var button = document .getElementById('button' ).addEventListener('click' , buttonClick);function buttonClick ( ) { document .getElementById('header-title' ).textContent = 'change' ; document .querySelector('#main' ).style.backgroundColor = 'red' ; }
點擊Click Here後Title的文字會變成change並且背景色改變為紅色
印出事件本身 會出現很多事件本身可以使用的方法(properties)例如 滑鼠位置 className altkey等等
1 2 3 4 5 var button = document .getElementById('button' ).addEventListener('click' , buttonClick);function buttonClick (e ) {console .log(e);}
只擷取一部份
properties使用方式介紹跟結果: 這邊列出的properties都可以在上面印出來的MouseEvent裡面找到
1 2 3 4 5 6 7 8 9 10 11 12 13 var button = document .getElementById('button' ).addEventListener('click' , buttonClick);function buttonClick (e ) {console .log(e.target);console .log(e.target.id);console .log(e.target.className);console .log(e.target.classList);console .log(e.type);var output = document .getElementById('output123' );output.innerHTML = '<h3>' +e.target.id+'</h3>' ; }
印出的結果
把取得的id文字加入欄位中用文字串接的方式
滑鼠位置擷取 clientX,Y 滑鼠在瀏覽器上的位置 offsetX,Y 滑鼠在物件元素上面的位置 1 2 3 4 5 6 7 function buttonClick (e ) {console .log(e.clientX);console .log(e.clientY);console .log(e.offsetX);console .log(e.offsetY);}
當點擊Click Here之後會印出它們的位置:
判斷是否按住該按鍵進而可以做不同的功能 當按住該按鍵的時候會顯示true放開則顯示false,可以用做if判斷式來做不同的功能
如: 當按住alt時,顯示XXX之類的功能
1 2 3 4 5 6 function buttonClick (e ) {console .log(e.altKey);console .log(e.ctrlKey);console .log(e.shiftKey);}
滑鼠事件簡介+一個小練習 click dblclick mousedown mouseup 1 2 3 4 5 6 7 8 9 10 11 var button = document .getElementById('button' )button.addEventListener('click' , runEvent); button.addEventListener('dblclick' , runEvent); button.addEventListener('mousedown' , runEvent); button.addEventListener('mouseup' , runEvent); function runEvent (e ) { console .log('Event type:' +e.type); }
印出的類型:
為了展示mouseenter event創造一個新的黃色div
mouseenter & mouseleave / mouseover & mouseout 當滑鼠進出的瞬間就會印出方法runEvent
他們的功能很像不過有差異:
mouseenter & mouseleave只會在進出物件的時候會觸發 mouseover & mouseout 則是除了進出之外碰到內部的子元素(這邊的例子是HELLO)都會觸發
1 2 3 4 5 6 7 8 9 10 var box = document .getElementById('box' );box.addEventListener('mouseenter' , runEvent); box.addEventListener('mouseleave' , runEvent); box.addEventListener('mouseover' , runEvent); box.addEventListener('mouseout' , runEvent); function runEvent (e ) { console .log('Event type:' +e.type); }
mousemove 當滑鼠在物件內移動時觸發事件
1 2 3 4 5 6 7 8 var button = document .getElementById('button' );var box = document .getElementById('box' );box.addEventListener('mousemove' , runEvent); function runEvent (e ) { console .log('Event type:' +e.type); }
通常觸發次數很高
加上滑鼠的位置呈現在頁面上 先抓取id後並指派給output變數,抓取box id指派給box變數, 並把box加入事件監聽使用mousemove並印出它的value呈現在頁面上
這個output的位置
1 2 3 4 5 6 7 8 9 10 var box = document .getElementById('box' );var output = document .getElementById('output123' );box.addEventListener('mousemove' , runEvent); function runEvent (e ) { output.innerHTML = '<h3>MouseX: ' +e.offsetX+'<h/3><h3>MouseY:' +e.offsetY+'</h/3>' ; }
印出來的結果位置:
下一步我們要做的事情是把抓取到的滑鼠座標位置轉換成RGB的數字,進而讓我們在物件內移動滑鼠的時候改變顏色 1 2 3 4 5 6 7 8 9 10 11 var box = document .getElementById('box' );var output = document .getElementById('output123' );box.addEventListener('mousemove' , runEvent); function runEvent (e ) {box.style.backgroundColor = "rgb(" +e.offsetX+"," +e.offsetY+",40)" ; }
結果如下:
處理上方的Add items
1 2 3 4 5 6 7 8 9 10 var itemInput = document .querySelector('input[type="text"]' );var form = document .querySelector('form' );itemInput.addEventListener('keydown' , runEvent); function runEvent (e ) { console .log('Event type:' +e.type); }
簡介一些其他Event keydown 按下鍵盤時觸發 keyup 離開按紐時觸發 keypress 按住按紐時觸發 focus 按在input中的時候觸發 blur 離開focus時觸發 cut 剪下內容時觸發 paste 貼上內容時觸發 input 在input內部做的任何事情跟內文有關係的打字剪下貼上等等都會觸發 change 當抓取物件發生改變的時候觸發 submit 當按下submit按鍵後觸發 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 itemInput.addEventListener('keydown' , runEvent); itemInput.addEventListener('keyup' , runEvent); itemInput.addEventListener('keypress' , runEvent); itemInput.addEventListener('focus' , runEvent); itemInput.addEventListener('blur' , runEvent); itemInput.addEventListener('cut' , runEvent); itemInput.addEventListener('paste' , runEvent); itemInput.addEventListener('input' , runEvent); itemInput.addEventListener('change' , runEvent); itemInput.addEventListener('submit' , runEvent);
讓輸入的文字內容完整地呈現在瀏覽器上 1 2 3 4 5 6 7 8 9 10 11 12 13 14 var itemInput = document .querySelector('input[type="text"]' );var form = document .querySelector('form' );itemInput.addEventListener('keydown' , runEvent); function runEvent (e ) { console .log('Event type:' +e.type); console .log(e.target.value); document .getElementById('output123' ).innerHTML = '<h3>' +e.target.value+'</h3>' ; }
結果
當選取下拉式選單的時候觸發事件使用”change”事件 一點選下拉選單就會觸發事件並印出事件類型
1 2 3 4 5 6 7 var select = document .querySelector('select' );select.addEventListener('change' , runEvent); function runEvent (e ) { console .log('Event type:' +e.type); }
印出選取的下拉式選單的值 使用console.log(e.target.value);
1 2 3 4 5 6 7 8 9 10 var select = document .querySelector('select' );select.addEventListener('change' , runEvent); function runEvent (e ) { console .log('Event type:' +e.type); console .log(e.target.value); }
按下submit按鍵後印出type 1 2 3 4 5 6 7 8 var form = document .querySelector('form' );form.addEventListener('submit' , runEvent); function runEvent (e ) { e.preventDefault(); console .log('Event type:' +e.type); }
JavaScript DOM Crash Course Part - 4 使用上面三個part做出一個真正的小作品來呈現
作品程式碼
作品Item Lister
功能: 可以在Add items品項並且在submit後加入下方的items 點X有刪除功能 右上角可以搜尋已加入的items(filter) HTML: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 <body > <header id ="main-header" class ="bg-success text-white p-4 mb-3" > <div class ="container" > <div class ="row" > <div class ="col-md-6" > <h1 id ="header-title" > Item Lister</h1 > </div > <div class ="col-md-6 align-self-center" > <input type ="text" class ="form-control" id ="filter" placeholder ="Search Items..." > </div > </div > </div > </header > <div class ="container" > <div id ="main" class ="card card-body" > <h2 class ="title" > Add Items</h2 > <form id ="addForm" class ="form-inline mb-3" > <input type ="text" class ="form-control mr-2" id ="item" > <input type ="submit" class ="btn btn-dark" value ="Submit" > </form > <h2 class ="title" > Items</h2 > <ul id ="items" class ="list-group" > <li class ="list-group-item" > Item 1 <button class ="btn btn-danger btn-sm float-right delete" > X</button > </li > <li class ="list-group-item" > Item 2 <button class ="btn btn-danger btn-sm float-right delete" > X</button > </li > <li class ="list-group-item" > Item 3 <button class ="btn btn-danger btn-sm float-right delete" > X</button > </li > <li class ="list-group-item" > Item 4 <button class ="btn btn-danger btn-sm float-right delete" > X</button > </li > </ul > </div > </div > </div > </div > <script src ="dom.js" > </script > </body >
JS: 取得submit的值並且加入Items最底層 輸入123最底部加入123
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 var form = document .getElementById("addForm" );var itemList = document .getElementById("items" );form.addEventListener("submit" , addItem); function addItem (e ) { e.preventDefault(); var newItem = document .getElementById("item" ).value; var li = document .createElement("li" ); li.className = "list-group-item" ; li.appendChild(document .createTextNode(newItem)); var deleteBtn = document .createElement("button" ); deleteBtn.className = 'btn btn-danger btn-sm float-right delete' ; deleteBtn.appendChild(document .createTextNode('X' )); li.appendChild(deleteBtn); itemList.appendChild(li); }
刪除加入的items confirm()
用來跳出需要使用者確認的對話視窗,對話視窗中會有確定及取消兩個按鈕。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 itemList.addEventListener('click' , deleteItem); function deleteItem (e ) { if (e.target.classList.contains('delete' )) { if (confirm("Are you sure you want to delete?" )) { var li = e.target.parentElement; itemList.removeChild(li); } } }
filter篩選內容 indexOf()
方法返回啟動它的對像String中第一次出現的指定值的索引,從fromIndex處進行搜索。如果未找到該值,則返回-1。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 var filter = document .getElementById("filter" );filter.addEventListener("keyup" , filterItems); function filterItems (e ) { var text = e.target.value.toLowerCase(); var items = document .querySelectorAll('li' ); Array .from(items).forEach(function (item ) { var itemName = item.firstChild.textContent; if (itemName.toLowerCase().indexOf(text) != -1 ) { item.style.display = 'block' ; } else { item.style.display = 'none' ; } }); }