# JS練習_記帳本 製作一個記帳簿,可以增加收入及支出,並呈現加總金額。 - 成品畫面: ![](https://i.imgur.com/YcE8kKA.png) - [成果網頁](https://chrislinlin.github.io/my-projects/mentor_mission/mission_24/index.html) ## 功能 - [x] 每個品項記載名稱及金額,並依照金額給予特定屬性。 - [x] 單一頁面實現新增、刪除品項及各項加總。 ## html - 中間的HISTORY是用容器包覆著`ul`,每筆新增的項目會表示在`ul`裡及`form` - 最下面則是用`form`讓使用者填寫新增的項目。 ## css - 使用變數儲存陰影的設定,可以迅速且方便的取用。 ```.css :root{ --box-shadow: 0 1px 3px rgba(0,0,0,.12), 0 1px 2px rgba(0,0,0.24); /*取用時以box-shadow: var(--box-shadow)即可取用*/ } ``` - 在選擇器上,使用`<tag>:first-of-type`指的是某父元素下相同型別子元素中的第一個,像是本次`div:first-of-type` 就是在某父型別下的第一個div。 - [first-type-of 小科普](https://developer.mozilla.org/en-US/docs/Web/CSS/:first-of-type) - 在容器右邊設定邊線,達成中間有分隔線的效果。 ```.css .inc-exp-container >div:first-of-type{ border-right: 1px solid #dedede } ``` - 在父元素容器,進行切分,利用flex設定為一,使子元素自動平分空間 ```.css .inc-exp-container >div{ flex: 1; text-align: center; } ``` ## JavaScript ### 步驟 - 輸入要新增的內容呈現在上面列表 - 上面列表內容金額自動加總 - 金額正數呈現綠色,金額負數呈現紅色 - 點選刪除鍵,總金額自動計算,列表內容刪除 ### addItem() 使輸入的項目,新增至上方HISTORY,同時也新增一個刪除按鈕。 - 將原先`li`標籤設定minus屬性,並設定參數條件,若符合條件,則移除minus屬性並新增plus屬性。 - 當選擇在history刪除項目時,點選==x==觸發事件,記得要加上`last()`,不然會把所有輸入的項目都刪掉,不會只刪一個。 - [last 小科普](https://api.jquery.com/last/) - append()/ appendTo() 兩種方法功能相同,都是將目標加入容器之後但語法不同。 - (表達式).append(參數) - (加入物(參數)).appendTo(容器(表達式)) ```.js= //add item in history function addItem(name, amount, id ,transactions){ var item_str = '<li class =minus>'+name+'<span>'+amount+'</span>'+'<button class = "delete-btn" data-id="'+id+'">x</button>'; $('#list').append(item_str) if(amount>0){ $('li').toggleClass('minus') $('li').addClass('plus') } clearForm(); $('.delete-btn').last().click(function(){ $(this).parent().remove(); var id =$(this).data('id'); deleteItemFormLocalstorage(transactions, id); updateValues(); }) } ``` - [append to 小科普](https://api.jquery.com/appendto/) ### localstorage 建立一個變數`transactions`,將儲存在localstorage的資料拉出來,並利用`JSON parse()`將拉出來的資料轉換成陣列形式。 ```.js var transactions = JSON.parse(localStorage.getItem('myTransactions')) || []; ``` ### generateID() - 產生亂數代表決定我們要在列表新增多少項目。 - `Math.random()`:會產生0~1間的小數。 - `Math.floor()`:會將小數點捨去並回傳小於等於產生的亂數的最大整數。 - 乘上100000倍,代表產生亂數的數量。 ```.js function generateID(){ return Math.floor(Math.random()*1000000) }; ``` ### clearform () 每當新增項目時(要在addItem()呼叫它),會清除使用者輸入欄的值,讓使用者得進行下一次的輸入。 ```.js function clearForm(){ $('#form').find("input").val(""); } ``` ### deleteItemFormLocalStorage() 設定條件,要是id完全符合時,使用 `splice()`方法,刪除陣列項目, 再利用使用`JSON.stringify`,將資料陣列轉為字串重新更新localstorage。 - [splice()小科普](https://developer.mozilla.org/zh-TW/docs/Web/JavaScript/Reference/Global_Objects/Array/splice) ```.js function deleteItemFormLocalstorage(transactions, id){ transactions.forEach(function(item, index, arr){ if(item.id === id){ arr.splice(index, 1); } }); localStorage.setItem('myTransactions', JSON.stringify(transactions)); } ``` ```.js= var transactions = JSON.parse(localStorage.getItem('myTransactions')) || []; $(document).ready(function(){ if(transactions.length >0){ initHistory(transactions); } $("#form").find('button').click(function(e){ e.preventDefault(); var name = $('#text').val(); var amount = $('#number').val(); var id = generateID() addItem(name, amount, id, transactions); //push()讓陣列可以丟進內容 transactions.push({id: id, name: name, amount: amount}); localStorage.setItem('myTransactions', JSON.stringify(transactions)); updateValues(); }) }) ``` ### updateValue() 1. 處理陣列的金額,利用`map()`運算回傳新的陣列 2. 每一筆交易加總,使用`reduce()`方法,抓取每一項目的金額進行加總 - reduce() ```.js= const sum = array.reduce((accumulator, element) => { return accumulator + element; }, 0); ``` - [reduce()小科普](https://developer.mozilla.org/zh-TW/docs/Web/JavaScript/Reference/Global_Objects/Array/Reduce) 3. 計算收入/ 支出/ 總數金額,使用`filter()`方法,設定函式計算,經過運算,回傳新的陣列。 - filter() 得到元素/ 物件集合中的符合的表達式,把要的物件/元素選出來 ```.html <ul> <li>list item 1</li> <li>list item 2</li> <li>list item 3</li> <li>list item 4</li> <li>list item 5</li> <li>list item 6</li> </ul> ``` ```.js= $('li').filter(':even').css('background-color', 'red'); ``` 那選出來的元素會是索引號為偶數得物件,然後我們用css讓他變紅色 ![](https://i.imgur.com/ORy4byy.png) - [filter()小科普](https://developer.mozilla.org/zh-TW/docs/Web/JavaScript/Reference/Global_Objects/Array/filter) 4. 加入內文至選定的元素 5. 在函式initHistory 及點擊事件時呼叫他,使事件發生時能更新資訊。 ```.js function updateValues() { const amounts = transactions .map(function(transaction) { return transaction.amount; }) // reduce()方法:累加陣列中數值 const total = parseFloat(amounts .map(Number) //單純的amount是字串陣列 .reduce((function(accumulator, item_str) { return accumulator += item_str; // accumulator = accumulator + item; }),0)) .toFixed(2); // console.log(total) // filter()方法: 經過內部函式處理後,將通過之元素回傳為新陣列 // https://developer.mozilla.org/zh-TW/docs/Web/JavaScript/Reference/Global_Objects/Array/filter const income = parseFloat(amounts .filter(function(item_str) { return item_str > 0; }) .reduce((function(accumulator, item_str) { return accumulator -= item_str; }),0))*-1 .toFixed(2); console.log(income) const expense = parseFloat((amounts .filter(function(item_str) { return item_str < 0; }) .reduce((function(accumulator, item_str) { return accumulator -= item_str; //acc=acc-item }),0) * -1)) .toFixed(2); // console.log(expense) $('#balance').text(`$${total}`); $('#money-plus').text(`$${income}`); $('#money-minus').text(`$${expense}`); } ``` ### initHistory() 用 `forEach()`方法跑一次物件的資料,等呼叫函式時,可以直接顯示。 ```.js function initHistory(transactions){ transactions.forEach(function(item){ addItem(item.name, item.amount, item.id, transactions)//item.id也要記得加 }) updateValues(); } ``` ###### tags: `javascript`