我正在尝试弄清楚如何在刷新页面后保持“Mark as Read”为“Mark as Unread”。反之亦然。我如何使用localStorage保存数据?到目前为止,这是我的“Mark as Read”代码: 第一个 我单击“标记为已读”,它变成了“标记为未读”。但刷新页面后,它又回到了“标记为已读”。如何避免这种情况?
<script>
function readunread() {
currentvalue = document.getElementById("readunread").value;
if (currentvalue == "Mark as Unread") {
document.getElementById("readunread").value = "Mark as Read";
// 1. Update the localstorage
localStorage.setItem("readunread", "Mark as Read");
} else {
document.getElementById("readunread").value = "Mark as Unread";
// 1. Update the localstorage
localStorage.setItem("readunread", "Mark as Unread");
}
}
</script>
<input
type="button"
value="Mark as Read"
id="readunread"
onclick="readunread();"
/>
<script>
// 2. Get the value from the local storage
function loadInitialValue() {
const localValue = localStorage.getItem("readunread");
console.log(localValue);
if (localValue == "Mark as Unread") {
document.getElementById("readunread").value = "Mark as Unread";
} else {
document.getElementById("readunread").value = "Mark as Read";
}
}
loadInitialValue(); // Make sure to call the function
</script>
为了使用localStorage作为持久性数据存储来管理项的已读/未读状态,您需要序列化(un)读取状态作为某种字符串以作为值存储在存储区中(因为localStorage只存储字符串值),然后在检索该值时对其进行反序列化。JSON是序列化格式的一个可访问选择,因为它自然地表示许多JavaScript数据结构,并且易于parse/stringify。 像这样的问题总是很难在一个工作的代码片段中演示,因为Stack Overflow的代码片段环境是沙盒的,并且阻止访问localStorage之类的东西,所以当你试图使用这些特性时,由于缺乏权限,会抛出一个运行时异常。 下面我提供了一个自包含的例子,使用基本的functional programming技术来存储一个条目列表的已读/未读状态,以保持代码的组织性。你可以将代码复制粘贴到你电脑上的本地HTML文件中,然后使用本地静态文件web服务器提供(例如,Deno或Python等)来查看它的工作情况。我已经为您提供了详细的注解,以解释程序的每一步都发生了什么。 如果要在测试演示时检查localStorage的状态,请参阅问题How to view or edit localStorage?。
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>LocalStorage: read/unread items</title>
<style>
/* Just some styles for this example: styling is up to you */
* { box-sizing: border-box; }
body { font-family: sans-serif; }
.toggle-status {
font-size: 1rem;
padding: 0.25rem;
width: 8rem;
}
#list {
list-style: none;
padding: 0;
display: flex;
flex-direction: column;
gap: 0.5rem;
align-items: flex-start;
}
.item {
display: flex;
gap: 1rem;
align-items: center;
}
.item.read > .item-content { font-weight: normal; }
.item.unread > .item-content { font-weight: bold; }
</style>
<script type="module">
// Get the state of all of the read/unread items from localStorage
// as an object:
function getStatusMap () {
try {
// Get the JSON value from local storage:
// if it doesn't exist, it will be null, so use a default value instead:
// a JSON string representing an empty object:
const storageValue = window.localStorage.getItem('read_status_map') ?? '{}';
// Parse the string value into an actual object:
const readStatusMap = JSON.parse(storageValue);
// Return the value if it's a plain object:
if (
typeof readStatusMap === 'object'
&& readStatusMap !== null
&& !Array.isArray(readStatusMap)
) return readStatusMap;
// Else throw an error because it was an invalid value:
throw new Error('Unepxected value');
}
catch (ex) {
// Catch any exception which might have occurred.
// You can handle it however you want (or just ignore it).
// For example, you could print it
// to the console error stream to view it:
console.error(ex);
// Return an empty object as the default:
return {};
}
}
// Update the localStorage state of all the read/unread items:
function setStatusMap (statusMap) {
const json = JSON.stringify(statusMap);
const storageValue = window.localStorage.setItem('read_status_map', json);
}
// Update the read/unread status for a single item:
function updateStatus (statusMap, listItemElement, isReadStatus) {
const button = listItemElement.querySelector(':scope > button.toggle-status');
// Depending on the current status, update the action button's text
// to describe the next (opposite) action:
button.textContent = `Mark as ${isReadStatus ? 'unread' : 'read'}`;
// Get the ID from the list item's data attribute:
const {id} = listItemElement.dataset;
// Get the state object of the current item from the status map object,
// OR create one if it doesn't exist yet. You can store other information
// about each item here, but — in this example — only the ID (string)
// and read status (boolean) properties are stored:
const status = statusMap[id] ??= {id, isRead: false};
// Update the read status of the item:
status.isRead = isReadStatus;
// Update the whole state in localStorage:
setStatusMap(statusMap);
// Optional: update the list item's read/unread class.
// This can help with applying CSS styles to the items:
if (isReadStatus) {
listItemElement.classList.add('read');
listItemElement.classList.remove('unread');
}
else {
listItemElement.classList.remove('read');
listItemElement.classList.add('unread');
}
}
// A convenience function which toggles between read/unread for an item:
function toggleStatus (statusMap, listItemElement) {
// Get the ID from the list item's data attribute:
const {id} = listItemElement.dataset;
// Get the current status (or false by default if it doesn't exist yet):
let isRead = statusMap[id]?.isRead ?? false;
// Toggle it to the opposite state:
isRead = !isRead;
// Update it:
updateStatus(statusMap, listItemElement, isRead);
}
// Now, using the functions above together:
function main () {
// Get the initial read/unread status map:
const statusMap = getStatusMap();
// Get an array of the item elements:
const listItemElements = [...document.querySelectorAll('#list > li.item')];
for (const listItemElement of listItemElements) {
// Get the ID from the list item's data attribute:
const {id} = listItemElement.dataset;
// Set the initial read status for each item to what was found
// in localStorage, or if nothing was found then set to false by default:
const initialStatus = statusMap[id]?.isRead ?? false;
updateStatus(statusMap, listItemElement, initialStatus);
const button = listItemElement.querySelector(':scope > button.toggle-status');
// Set an action for each item's toggle button: when it is clicked,
// toggle the status for that item. Formally, this is called "binding an
// event listener callback to the button's click event":
button.addEventListener(
'click',
() => toggleStatus(statusMap, listItemElement),
);
}
}
// Invoke the main function:
main()
</script>
</head>
<body>
<!--
A list of items, each with:
- a unique ID
- a toggle button,
- and some text content
-->
<ul id="list">
<li class="item" data-id="cc9e88ce-3ed4-443a-84fc-fa7147baa025">
<button class="toggle-status">Mark as read</button>
<div class="item-content">First item content</div>
</li>
<li class="item" data-id="23a9204c-905f-48db-9f6a-deb3c8f82916">
<button class="toggle-status">Mark as read</button>
<div class="item-content">Second item content</div>
</li>
<li class="item" data-id="18b47e4c-635f-49c0-924e-b9088538d08a">
<button class="toggle-status">Mark as read</button>
<div class="item-content">Third item content</div>
</li>
<li class="item" data-id="ed2aacca-64f0-409d-8c1b-d1bdcb7c6058">
<button class="toggle-status">Mark as read</button>
<div class="item-content">Fourth item content</div>
</li>
<li class="item" data-id="0fce307b-656a-4102-9dc9-5e5be17b068d">
<button class="toggle-status">Mark as read</button>
<div class="item-content">Fifth item content</div>
</li>
<!-- ...etc. -->
</ul>
</body>
</html>
3条答案
按热度按时间sulc1iza1#
在脚本中,您需要更改两项内容:
uqdfh47h2#
为了使用
localStorage
作为持久性数据存储来管理项的已读/未读状态,您需要序列化(un)读取状态作为某种字符串以作为值存储在存储区中(因为localStorage
只存储字符串值),然后在检索该值时对其进行反序列化。JSON是序列化格式的一个可访问选择,因为它自然地表示许多JavaScript数据结构,并且易于parse/stringify。像这样的问题总是很难在一个工作的代码片段中演示,因为Stack Overflow的代码片段环境是沙盒的,并且阻止访问
localStorage
之类的东西,所以当你试图使用这些特性时,由于缺乏权限,会抛出一个运行时异常。下面我提供了一个自包含的例子,使用基本的functional programming技术来存储一个条目列表的已读/未读状态,以保持代码的组织性。你可以将代码复制粘贴到你电脑上的本地HTML文件中,然后使用本地静态文件web服务器提供(例如,Deno或Python等)来查看它的工作情况。我已经为您提供了详细的注解,以解释程序的每一步都发生了什么。
如果要在测试演示时检查localStorage的状态,请参阅问题How to view or edit localStorage?。
fnvucqvd3#
你已经很接近了。剩下的就是使用本地存储了。为此,用下面的代码替换你的JavaScript: