--- tags: DOM,Event,JavaScript --- # Reading-list 閱讀清單實作 ###### tags: `DOM` `Event` `JavaScript` 這次做的是一個小的閱讀書單,Demo在[CodePen](https://codepen.io/running_pie/pen/bGowwbB),可以直接參考。 樣式的部分就不多談了,這篇文章主要紀錄的是:利用 JS 寫出想要的功能。整個書單的製作,主要可以學習到關於 DOM - 文件物件模型 的技巧,算是讓自己更熟悉概念的小作品。 ## 功能 1. 按下刪除鈕之後,書籍會從清單上消失 2. 按下增加鈕之後,可以將想要增加的書顯示到書單內 3. 勾選隱藏全部,可以將書單內的書隱藏 4. 客製的過濾器 5. 使用 tab 頁籤功能 ## HTML 結構 - #page-banner > 裡面有表單和輸入框 #search-books - #book-list > ul > li,內容包含書本名 .name、刪除鈕 .delete - .below-section > 表單 #add-book > 隱藏功能 #hide / 增加功能 .add-book - #tab-content > 頁籤 .tabs (ul>li*2) / 面板 .panel ## 功能實作 使用DOM來新增或移除元件節點,先定位到要操作的節點,加上事件監聽器來監聽元件上是否有事件發生,才能觸發事件所含有的函式。 > 1. 按下刪除鈕之後,書籍會從清單上消失 我們監聽整個book-list ul,當事件的target具有class="delete"(也就是button元件),被點擊時,往它的上一層元件(li)定位,再使用parentElement.removeChild,刪除整個li節點。 ```jsx= //功能一,按下刪除鈕之後,書籍會從清單上消失 const list = document.querySelector("#book-list ul"); list.addEventListener("click", function(e){ if(e.target.className == "delete"){ //跳到父層li,才能刪除這本書 const li = e.target.parentElement; //刪除方法: removeChild,但要先再往上到父層ul,再往下刪除 li.parentElement.removeChild(li); }; }); ``` > 2. 按下增加鈕之後,可以將想要增加的書顯示到書單內 定位在表單,監聽是否按下增加按鈕,如果按下、送出,先取得input的text value,接著建造新的元件>賦予內容和class>將元件依序加到li裡>將li加到list裡。 ```jsx= //功能二,輸入書名、按下增加鈕之後,可以將想要增加的書顯示到書單內 const addForm = document.forms["add-book"]; addForm.addEventListener("submit", function(e){ e.preventDefault();//避免送出之後的頁面重新整理 const nameValue = addForm.querySelector('input[type="text"]').value; //create elements const li = document.createElement('li'); const bookName = document.createElement('p'); const deleteBtn = document.createElement('button'); //add content deleteBtn.textContent = 'Delete'; bookName.textContent = nameValue; //add classes bookName.classList.add("name"); deleteBtn.classList.add("delete"); //insert the elements into the HTML format (append to document) li.appendChild(bookName); li.appendChild(deleteBtn); list.appendChild(li); }); ``` > 3. 勾選隱藏全部,可以將書單內的書隱藏 定位在checkbox上,看是否有被勾選,有的話,改變list的顯示狀態,沒有的話,list的顯示狀態設定為原本的樣子。 ```jsx= //功能三,勾選隱藏全部,可以將書單內的書隱藏 const hideBox = document.querySelector("#hide"); hideBox.addEventListener('change',function(e){ //先檢查有沒有勾選 if(hideBox.checked){ //有勾選,隱藏書單 list.style.display = "none"; }else{ //沒有勾選,顯示書單 list.style.display = "block"; } }); ``` > 4. 客製的過濾器 直接定位在表單 #search-books 的input上,將讀取的文字value轉成小寫之後,和list的li>p class="name"的文字內容比較(一樣要轉成全部小寫),如果有對應到的話會呈現在書單上,沒有對應到的話就是空的。 ```jsx= //功能四,客製的過濾器 const searchBar = document.forms["search-books"].querySelector('input'); searchBar.addEventListener("keyup", function(e){ //取得使用者輸入的文字,並確定所有字母都轉成小寫,方便對比 const term = e.target.value.toLowerCase(); //重新改寫list 的標題為小寫字母 const books = list.getElementsByTagName("li"); Array.from(books).forEach(function(book){ //grab the book title const title = book.firstElementChild.textContent; //indexOf 會比對內容,如果不相符的話,回傳-1 if(title.toLowerCase().indexOf(term) != -1){ book.style.display = "flex"; }else{ book.style.display = "none"; } }); }); ``` > 5. 使用tab 頁籤功能 分別定位頁籤和內容版面,當頁籤(li)被點擊時,此元件會成為目標版面,如果內容版面的其中一頁跟目標版面相符,在此內容版面上加上active的class,同時對其他內容版面移除active的class。 ```jsx= //功能五,使用tab 頁籤功能 //tab content const tabs = document.querySelector(".tabs"); const panels = document.querySelectorAll(".panel"); tabs.addEventListener("click",function(e){ if(e.target.tagName == "LI"){ const targetPanel = document.querySelector(e.target.dataset.target); panels.forEach(function(panel){ if(panel == targetPanel){ panel.classList.add('active'); }else{ panel.classList.remove('active'); } }) } }); ```