我对 JS 相当陌生,我刚刚完成创建预算/财务跟踪器,我希望能够保存数据,这样当我使用 localStorage 刷新页面时数据就不会消失。我该怎么做呢?我以前从未使用过 LocalStorage,因此我需要一些有关如何将其添加到我的代码中的帮助。我尝试使用 localStorage 但我无法理解它是如何工作的。我所知道的是 localStorage.setItem(key, value) 来保存键/值对和 localStorage.getItem(Key) 来调用它,但我不完全理解如何真正使用它们。
HTML
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<script src="https://kit.fontawesome.com/0cd8470e78.js" crossorigin="anonymous"></script>
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=NTR&display=swap" rel="stylesheet">
<link rel="stylesheet" href="finance.css">
<title>Document</title>
</head>
<body>
<div id="container">
<h1 class="title">Finance Tracker</h1>
<!-- Finance Box -->
<div class="finance_box">
<!-- Income -->
<div class="finance_div income_div">
<div>
<input type="text" id="income" placeholder="Income...">
<input type="number" id="income_amount" placeholder="Amount...">
</div>
<button class="add_finance" id="add_income" data-add="income">Add</button>
</div>
<!-- Expense -->
<div class="finance_div expense_div">
<div>
<input type="text" id="expense" placeholder="Expense...">
<input type="number" id="expense_amount" placeholder="Amount...">
</div>
<button class="add_finance" id="add_expense" data-add="expense">Add</button>
</div>
<!-- Investment -->
<div class="finance_div investment_div">
<div>
<input type="text" id="investment" placeholder="Investment...">
<input type="number" id="investment_amount" placeholder="Amount...">
</div>
<button class="add_finance" id="add_investment" data-add="investment">Add</button>
</div>
</div>
<!-- Finance Box -->
<!-- Tracker Box -->
<div class="tracker_box">
<div class="headers">
<h1 class="tracker_titles">Income</h1>
<h1 class="tracker_titles">Expense</h1>
<h1 class="tracker_titles">Investment</h1>
</div>
<div class="content_box">
<!-- Box type = income -->
<div class="tracked_div" id="inc" data-boxtype="income">
<!-- <div class="tracked">
<input type="text" placeholder="Testing" class="track_name">
<input type="number" placeholder="123" class="track_amount">
<div class="btn_div">
<button class="edit_item edit"><i class="fa-solid fa-pen-to-square"></i></button>
<button class="check_item check"><i class="fa-solid fa-check"></i></button>
<button class="delete_item delete"><i class="fa-solid fa-trash"></i></button>
</div>
</div> -->
</div>
<!-- Box type = expense -->
<div class="tracked_div" id="exp" data-boxtype="expense">
</div>
<!-- Box type = investments -->
<div class="tracked_div" id="invest" data-boxtype="investment">
</div>
</div>
</div>
<!-- Tracker Box -->
<!-- Total Box -->
<div class="total_box">
<div class="totals">
<div class="income_total_div">
<h1 class="currency"></h1>
<h1 id="income_total"></h1>
</div>
<div class="expense_total_div">
<h1 class="currency"></h1>
<h1 id="expense_total"></h1>
</div>
<div class="investment_total_div">
<h1 class="currency"></h1>
<h1 id="investment_total"></h1>
</div>
</div>
<div class="net_total_box">
<h1>Net Total</h1>
<h1 id="net_total"></h1>
</div>
</div>
<!-- Total box -->
</div>
<script src="finance.js"></script>
<!-- <script src="dummy.js"></script> -->
</body>
</html>
CSS
* {
margin: 0;
padding: 0;
font-family: "NTR", sans-serif;
font-family: "Madimi One", sans-serif;
}
body {
background: #161A30;
color: white;
}
#container {
width: 100vw;
height: 100vh;
display: flex;
flex-direction: column;
justify-content: space-between;
}
#expense_tracker {
border-left: 1px solid black;
border-right: 1px solid black;
}
#net_total {
color: #36abab;
}
#income_total {
display: flex;
justify-content: center;
align-items: center;
font-size: 28px;
color: #00af75;
}
#expense_total {
display: flex;
justify-content: center;
align-items: center;
font-size: 28px;
color: #e13056;
}
#investment_total {
display: flex;
justify-content: center;
align-items: center;
font-size: 28px;
color: #F2F597;
}
body::-webkit-scrollbar {
display: none;
}
.edit_item,
.delete_item,
.check_item {
padding: 0.5rem;
}
.title {
width: 100%;
height: 8vh;
font-size: 40px;
display: flex;
justify-content: center;
align-items: center;
}
.finance_box {
width: 100%;
height: 10vh;
display: flex;
justify-content: space-around;
align-items: center;
margin-bottom: 1rem;
}
.finance_div {
width: 100%;
height: 100%;
display: flex;
flex-direction: column;
justify-content: space-around;
align-items: center;
}
.finance_div div {
width: 100%;
display: flex;
justify-content: space-around;
align-items: center;
}
.finance_div input {
width: 40%;
border: none;
outline: none;
border-radius: 1px;
background-color: #B6BBC4;
font-size: 16px;
padding: 0.5rem 1rem;
text-align: center;;
}
.finance_div input::placeholder {
color: #0000002d;
}
.finance_div input:focus {
background-color: #ebf1fc;
}
.add_finance {
border: none;
outline: none;
border-radius: 1rem;
background: #F0ECE5;
padding: 0.3rem 2rem;
font-size: 22px;
letter-spacing: 3px;
transition: 0.1s ease-in-out;
}
.add_finance:hover {
cursor: pointer;
color: white;
background-color: #57c270;
}
.tracker_box {
height: 66vh;
min-height: 60vh;
max-height: 66vh;
display: flex;
flex-direction: column;
}
.headers {
width: 100%;
height: 5%;
margin-bottom: 1rem;
display: flex;
justify-content: space-around;
align-items: center;
}
.content_box {
width: 100%;
height: 90%;
display: flex;
justify-content: space-around;
}
.tracked_div {
width: 100%;
height: 100%;
background-color: #B6BBC4;
border-top: 1px solid black;
overflow-y: scroll;
}
.tracked_div:nth-child(2) {
border-left: 1px solid black;
border-right: 1px solid black;
}
.tracked_div::-webkit-scrollbar {
display: none;
}
.tracked {
width: 100%;
height: 5vh;
display: flex;
justify-content: space-between;
font-size: 18px;
}
.track_name {
width: 40%;
height: 100%;
color: rgb(0, 0, 0);
text-align: center;
font-size: 18px;
background: transparent;
border: none;
outline: none;
padding: 0 0.3rem;
}
.track_amount {
width: 35%;
height: 100%;
color: black;
padding: 0 0.2rem;
border: none;
outline: none;
text-align: center;
font-size: 18px;
background: transparent;
}
.edit_item,
.delete_item,
.check_item {
border: none;
cursor: pointer;
background: transparent;
font-size: 18px;
}
.check_item {
display: none;
}
.active {
display: block;
}
.non-active {
display: none;
}
.edit_item:hover {
color: rgb(3, 204, 3);
}
.check_item:hover {
color: rgb(3, 204, 3);
}
.delete_item:hover {
color: red;
}
.btn_div {
width: 20%;
height: 100%;
display: flex;
justify-content: space-around;
align-items: center;
}
.total_box {
width: 100%;
height: 15vh;
display: flex;
flex-direction: column;
justify-content: space-between;
align-items: center;
}
.totals {
width: 100%;
height: 25%;
display: flex;
justify-content: space-around;
align-items: center;;
}
.income_total_div,
.expense_total_div,
.investment_total_div {
display: flex;
}
.net_total_box {
width: 100%;
height: 70%;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
}
.net_total_box h1:nth-child(1) {
font-size: 28px;
}
input::-webkit-outer-spin-button,
input::-webkit-inner-spin-button {
-webkit-appearance: none;
margin: 0;
}
.currency {
display: flex;
justify-content: center;
align-items: center;
font-size: 25px;
margin-right: 0.2rem;
}
JavaScript
const incomeName = document.querySelector("#income");
const incomeAmount = document.querySelector("#income_amount");
const expenseName = document.querySelector("#expense");
const expenseAmount = document.querySelector("#expense_amount");
const investName = document.querySelector("#investment");
const investAmount = document.querySelector("#investment_amount");
// Add buttons
const addInfo = document.querySelectorAll(".add_finance");
// parent div of each category
let incomeContainer = document.querySelector('#inc');
const expenseContainer = document.querySelector('#exp');
const investContainer = document.querySelector('#invest');
// Total Counter
let incomeTotal = document.querySelector('#income_total');
let incCounter = 0;
let expenseTotal = document.querySelector('#expense_total');
let expCounter = 0;
let investTotal = document.querySelector('#investment_total');
let investCounter = 0;
// Net Total
let netTotal = document.querySelector('#net_total');
function userInput() {
addInfo.forEach(btn => {
btn.addEventListener('click', (e) => {
let data = e.currentTarget.dataset.add;
if (data === "income") {
addIncome();
netWorth();
};
if (data === "expense") {
addExpense();
netWorth()
};
if (data === "investment") {
addInvest();
};
})
})
}
function addIncome() {
if (incomeName.value !== "" && incomeAmount.value !== "") {
let trackedDiv = document.createElement('div');
let inputName = document.createElement('input');
let inputAmount = document.createElement('input');
let btnDiv = document.createElement('div');
let editBtn = document.createElement('button');
let checkBtn = document.createElement('button');
let deleteBtn = document.createElement('button');
trackedDiv.classList.add('tracked');
inputName.classList.add('track_name');
inputName.type = "text";
inputAmount.classList.add('track_amount');
inputAmount.type = "number";
btnDiv.classList.add('btn_div');
editBtn.classList.add('edit_item');
checkBtn.classList.add('check_item');
deleteBtn.classList.add('delete_item');
editBtn.innerHTML = `<i class="fa-solid fa-pen-to-square"></i>`;
checkBtn.innerHTML = `<i class="fa-solid fa-check"></i>`;
deleteBtn.innerHTML = `<i class="fa-solid fa-trash"></i>`;
inputName.disabled = "disabled";
inputAmount.disabled = "disabled";
inputName.value = incomeName.value;
inputAmount.value = incomeAmount.value;
incCounter += parseFloat(inputAmount.value);
let convertedIncome = new Intl.NumberFormat('en-US', {style: "currency", currency: "USD", minimumFractionDigits: 0, maximumFractionDigits: 2}).format(incCounter);
incomeTotal.innerText = convertedIncome;
trackedDiv.appendChild(inputName);
trackedDiv.appendChild(inputAmount);
btnDiv.appendChild(editBtn);
btnDiv.appendChild(checkBtn);
btnDiv.appendChild(deleteBtn);
trackedDiv.appendChild(btnDiv);
incomeContainer.appendChild(trackedDiv);
incomeName.value = "";
incomeAmount.value = "";
editBtn.addEventListener('click', () => {
editBtn.style.display = "none";
checkBtn.style.display = "inline-block";
deleteBtn.style.display = "none";
inputName.style.borderBottom = "thin solid black";
inputAmount.style.borderBottom = "thin solid black";
incCounter -= inputAmount.value;
let convertedIncome = new Intl.NumberFormat('en-US', {style: "currency", currency: "USD", minimumFractionDigits: 0, maximumFractionDigits: 0}).format(incCounter);
incomeTotal.innerText = convertedIncome;
inputName.disabled = false;
inputAmount.disabled = false;
})
checkBtn.addEventListener('click', () => {
if (inputName.value === "" || inputAmount.value === "") {
alert("Missing Information!");
} else {
checkBtn.style.display = "none";
editBtn.style.display = "inline-block";
deleteBtn.style.display = "inline-block";
inputName.style.borderBottomStyle = "none";
inputAmount.style.borderBottomStyle = "none";
incCounter += parseInt(inputAmount.value);
let convertedIncome = new Intl.NumberFormat('en-US', {style: "currency", currency: "USD", minimumFractionDigits: 0, maximumFractionDigits: 0}).format(incCounter);
incomeTotal.innerText = convertedIncome;
inputName.disabled = "disabled";
inputAmount.disabled = "disabled";
}
})
deleteBtn.addEventListener('click', (e) => {
let targetParent = e.currentTarget.closest(".tracked");
incCounter -= inputAmount.value;
let convertedIncome = new Intl.NumberFormat('en-US', {style: "currency", currency: "USD", minimumFractionDigits: 0, maximumFractionDigits: 0}).format(incCounter);
incomeTotal.innerText = convertedIncome;
netWorth();
incomeContainer.removeChild(targetParent);
})
} else {
alert("Missing Income Info!");
}
}
function addExpense() {
if (expenseName.value !== "" && expenseAmount.value !== "") {
let trackedDiv = document.createElement('div');
let inputName = document.createElement('input');
let inputAmount = document.createElement('input');
let btnDiv = document.createElement('div');
let editBtn = document.createElement('button');
let checkBtn = document.createElement('button');
let deleteBtn = document.createElement('button');
trackedDiv.classList.add('tracked');
inputName.classList.add('track_name');
inputName.type = "text";
inputAmount.classList.add('track_amount');
inputAmount.type = "number";
btnDiv.classList.add('btn_div');
editBtn.classList.add('edit_item');
checkBtn.classList.add('check_item');
deleteBtn.classList.add('delete_item');
editBtn.innerHTML = `<i class="fa-solid fa-pen-to-square"></i>`;
checkBtn.innerHTML = `<i class="fa-solid fa-check"></i>`;
deleteBtn.innerHTML = `<i class="fa-solid fa-trash"></i>`;
inputName.value = expenseName.value;
inputAmount.value = expenseAmount.value;
expCounter += parseInt(inputAmount.value);
let convertedExpense = new Intl.NumberFormat('en-US', {style: "currency", currency: "USD", minimumFractionDigits: 0, maximumFractionDigits: 0}).format(expCounter);
expenseTotal.innerText = convertedExpense;
trackedDiv.appendChild(inputName);
trackedDiv.appendChild(inputAmount);
btnDiv.appendChild(editBtn);
btnDiv.appendChild(checkBtn);
btnDiv.appendChild(deleteBtn);
trackedDiv.appendChild(btnDiv);
expenseContainer.appendChild(trackedDiv);
expenseName.value = "";
expenseAmount.value = "";
editBtn.addEventListener('click', () => {
editBtn.style.display = "none";
checkBtn.style.display = "inline-block";
deleteBtn.style.display = "none";
inputName.style.borderBottomStyle = "solid";
inputAmount.style.borderBottomStyle = "solid";
expCounter -= inputAmount.value;
let convertedExpense = new Intl.NumberFormat('en-US', {style: "currency", currency: "USD", minimumFractionDigits: 0, maximumFractionDigits: 0}).format(expCounter);
expenseTotal.innerText = convertedExpense;
inputName.disabled = false;
inputAmount.disabled = false;
})
checkBtn.addEventListener('click', () => {
if (inputName.value === "" || inputAmount.value === "") {
alert("Missing Information!");
} else {
checkBtn.style.display = "none";
editBtn.style.display = "inline-block";
deleteBtn.style.display = "inline-block";
inputName.style.borderBottomStyle = "none";
inputAmount.style.borderBottomStyle = "none";
expCounter += parseInt(inputAmount.value);
let convertedExpense = new Intl.NumberFormat('en-US', {style: "currency", currency: "USD", minimumFractionDigits: 0, maximumFractionDigits: 0}).format(expCounter);
expenseTotal.innerText = convertedExpense;
inputName.disabled = "disabled";
inputAmount.disabled = "disabled";
}
})
deleteBtn.addEventListener('click', (e) => {
let targetParent = e.currentTarget.closest(".tracked");
expCounter -= inputAmount.value;
let convertedExpense = new Intl.NumberFormat('en-US', {style: "currency", currency: "USD", minimumFractionDigits: 0, maximumFractionDigits: 0}).format(expCounter);
expenseTotal.innerText = convertedExpense;
netWorth();
expenseContainer.removeChild(targetParent);
})
} else {
alert("Missing Expense Info!");
};
}
function addInvest() {
if (investName.value !== "" && investAmount.value !== "") {
let trackedDiv = document.createElement('div');
let inputName = document.createElement('input');
let inputAmount = document.createElement('input');
let btnDiv = document.createElement('div');
let editBtn = document.createElement('button');
let checkBtn = document.createElement('button');
let deleteBtn = document.createElement('button');
trackedDiv.classList.add('tracked');
inputName.classList.add('track_name');
inputName.type = "text";
inputAmount.classList.add('track_amount');
inputAmount.type = "number";
btnDiv.classList.add('btn_div');
editBtn.classList.add('edit_item');
checkBtn.classList.add('check_item');
deleteBtn.classList.add('delete_item');
editBtn.innerHTML = `<i class="fa-solid fa-pen-to-square"></i>`;
checkBtn.innerHTML = `<i class="fa-solid fa-check"></i>`;
deleteBtn.innerHTML = `<i class="fa-solid fa-trash"></i>`;
inputName.value = investName.value;
inputAmount.value = investAmount.value;
investCounter += parseInt(inputAmount.value);
let convertedInvestment = new Intl.NumberFormat('en-US', {style: "currency", currency: "USD", minimumFractionDigits: 0, maximumFractionDigits: 0}).format(investCounter);
investTotal.innerText = convertedInvestment;
trackedDiv.appendChild(inputName);
trackedDiv.appendChild(inputAmount);
btnDiv.appendChild(editBtn);
btnDiv.appendChild(checkBtn);
btnDiv.appendChild(deleteBtn);
trackedDiv.appendChild(btnDiv);
investContainer.appendChild(trackedDiv);
investName.value = "";
investAmount.value = "";
editBtn.addEventListener('click', () => {
editBtn.style.display = "none";
checkBtn.style.display = "inline-block";
deleteBtn.style.display = "none";
inputName.style.borderBottomStyle = "solid";
inputAmount.style.borderBottomStyle = "solid";
investCounter -= inputAmount.value;
let convertedInvestment = new Intl.NumberFormat('en-US', {style: "currency", currency: "USD", minimumFractionDigits: 0, maximumFractionDigits: 0}).format(investCounter);
investTotal.innerText = convertedInvestment;
inputName.disabled = false;
inputAmount.disabled = false;
})
checkBtn.addEventListener('click', () => {
if (inputName.value === "" && inputAmount.value === "") {
alert("Missing investment Information!");
} else {
checkBtn.style.display = "none";
editBtn.style.display = "inline-block";
deleteBtn.style.display = "inline-block";
inputName.style.borderBottomStyle = "none";
inputAmount.style.borderBottomStyle = "none";
investCounter += parseInt(inputAmount.value);
let convertedInvestment = new Intl.NumberFormat('en-US', {style: "currency", currency: "USD", minimumFractionDigits: 0, maximumFractionDigits: 0}).format(investCounter);
investTotal.innerText = convertedInvestment;
inputName.disabled = "disabled";
inputAmount.disabled = "disabled";
}
})
deleteBtn.addEventListener('click', (e) => {
let targetParent = e.currentTarget.closest(".tracked");
investCounter -= inputAmount.value;
let convertedInvestment = new Intl.NumberFormat('en-US', {style: "currency", currency: "USD", minimumFractionDigits: 0, maximumFractionDigits: 0}).format(investCounter);
investTotal.innerText = convertedInvestment;
investContainer.removeChild(targetParent);
})
} else {
alert("Missing Investment Info!");
}
}
function netWorth() {
let sum = incCounter - expCounter;
let newSum = new Intl.NumberFormat("en-US", {style: "currency", currency: "USD", minimumFractionDigits: 0, maximumFractionDigits: 0}).format(sum);
netTotal.innerText = newSum;
}
netWorth();
userInput();
你的代码太长并且包含不必要的东西,CSS不是使用localStorage所必需的。
localStorage 是键值存储,键和值都应该是string。 如果您的键不是字符串,它们会自动转换为字符串。
但是在尝试保存键和值之前确保它们都是字符串是一个很好的做法。
示例
let userChosenNumber = 7
// setting a value
localStorage.setItem("luckyNumber", userChosenNumber.toString());
// getting a value
let theNumber = localStorage.getItem("luckyNumber");
// updating the value
localStorage.setItem("luckyNumber", "18");
// deleting the key-value pair
localStorage.removeItem("luckyNumber");
// clearing the localStorage (everything will be deleted)
localStorage.clear();