【问题标题】:Save dates to local storage将日期保存到本地存储
【发布时间】:2022-01-23 18:32:54
【问题描述】:

我正在构建一个带有同步待办事项列表的日历。我正在尝试根据用户输入将特定日期保存到本地存储。目前,待办事项已保存到本地存储,并显示在带有文本的待办事项列表和日历中,但如果我刷新页面,日历中的待办事项就会消失。

在本地存储中写入值:[object HTMLInputElement]

function saveTodosToLS() {
 const todosAsString = JSON.stringify(todos);
 localStorage.setItem("todos", todosAsString);
}

function loadTodos() {
 const todosAsString = localStorage.getItem('todos');
 todos = JSON.parse(todosAsString || '[]');
}

这是我苦苦挣扎的部分

function saveCalendarToLS() {
  const todoDateAsString = Date.parse('dateOfTodos');
  todoDateAsString = JSON.stringify(dateOfTodos);
  localStorage.setItem('dateOfTodos', todoDateAsString);
}

function loadTodosInLS() {
  const todoDateAsString = localStorage.getItem('dateOfTodos');
  dateOfTodos = Date.parse(todoDateAsString || '[]');
}

【问题讨论】:

  • Date.parse('dateOfTodos')是什么意思
  • @MirandaNilhag JSON 可以对数字进行字符串化。根据我的经验,将 JavaScript Date 对象序列化为 JSON 的最可靠方法是仅保存 Date 的内部 Unix 时间戳(来自 getTime()),然后使用 Date(number) 构造函数重新水化。
  • 您不能将 DOM 元素对象(如 HTMLInputElement)传递给 localStorage。你只能传递“POJO”对象(Plain Ol' JavaScript Objects)。
  • 我认为你应该更新那部分 JSON.stringify(todoDateAsString);
  • 编程时经常做的一件有用的事情是在出现问题时查看中间结果。在这种情况下,在浏览器控制台中运行 Date.parse('dateOfTodos');,并在运行问题中的代码后查看本地存储值的值可能会提供信息。

标签: javascript local-storage


【解决方案1】:
  • 您不应该使用使用全局变量(或任何类型的共享状态,实际上)来传递数据。当数据通过函数参数传入并通过返回值返回时,程序更容易理解
  • 练习防御性编程。这在 JavaScript 中是完全 essential 的,因为您没有使用编译器来强制执行类型安全。
    • 这实际上意味着实际验证函数参数参数的类型是否正确(例如stringobjectDate 等)并且它们的值在预期范围内(例如,不允许 1000 年后的 Date 值)。
  • 您的 Date.parse 调用完全不正确(为什么要传递非日期字符串文字?)

我会这样做:

(请参阅代码下方的注释项目符号列表)

const LOCALSTORAGE_KEY_TODOS = "todos";

function saveTodos( todosArray ) {
    if( !Array.isArray( todosArray ) ) throw new Error( "Expected 'todosArray' to be an array but encountered " + ( typeof todosArray ) ); // Defensive programing!

    const todosAsJson = JSON.stringify( todosArray );

    window.localStorage.setItem( LOCALSTORAGE_KEY_TODOS, todosAsJson );
}

/** Returns an array of todo objects. Returns an empty array if nothing is saved in the store. */
function loadTodos() {
    
    const todosAsJson = window.localStorage.getItem( LOCALSTORAGE_KEY_TODOS );
    if( todosAsJson ) {
        try {
            const todos = JSON.parse( todosAsJson );
            if( Array.isArray( todos ) ) return todos;
        }
        catch( err ) {
            console.error( "Couldn't load TODOs: %o", err );
        }
    }

    return [];
}

function saveCalendar( date, todos ) {
    if( !isDate( date ) ) throw new Error( "Expected 'date' to be a Date object." );
    if( !Array.isArray( todosArray ) ) throw new Error( "Expected 'todosArray' to be an array but encountered " + ( typeof todosArray ) );
    
    const dateKey = 'CALENDAR_' + getDateOnlyString( date );

    const todosAsJson = JSON.stringify( todosArray );
    window.localStorage.setItem( dateKey, todosAsJson );
}

/** Returns an array of todo objects. Returns an empty array if nothing is saved in the store for that date. The time component of 'date' is ignored. */
function loadCalendar( date ) {

    if( !isDate( date ) ) throw new Error( "Expected 'date' to be a Date object." );

    const dateKey = 'CALENDAR_' + getDateOnlyString( date );

    //

    const todosAsJson = window.localStorage.getItem( dateKey );
    if( todosAsJson ) {
        try {
            const todos = JSON.parse( todosAsJson );
            if( Array.isArray( todos ) ) return todos;
        }
        catch( err ) {
            console.error( "Couldn't load TODOs: %o", err );
        }
    }

    return [];
}

/** Returns boolean true or false */
function isDate( value ) {
    // https://stackoverflow.com/questions/643782/how-to-check-whether-an-object-is-a-date

    return value instanceof Date && ( typeof value.getMonth === 'function' );
}

/** Returns `date` formatted as ISO 8601 yyyy-MM-dd */
function getDateOnlyString( date ) {
    // HACK: https://stackoverflow.com/questions/25159330/how-to-convert-an-iso-date-to-the-date-format-yyyy-mm-dd
    return date.toISOString().substring(0,10); // "if it works..."
}
  • 避免发明你自己的首字母缩略词:我看到你使用“LS”是localStorage 的简写,但是这在 JavaScript 社区中并不常见,所以我会避免使用它并直接称它为是:localStorage
  • 您尚未发布 TODO object 的定义或规范,因此我的以下代码不会验证或验证有关 TODO 对象的任何内容,除非它们实际上是 object 值。
  • 避免使用魔法文字,无论是字符串还是数字。当您需要集合的一致键字符串(如 window.localStorage)时,您应该使用命名常量(例如 const LOCALSTORAGE_KEY_TODOS = 'todos';)。
  • 请记住,JavaScript 中的 Date 对象实际上表示日期和时间值,因此您不能只使用任何旧的Date 对象来表示只是 一个日期。如果您使用Date 它的Unix时间戳值(来自Date.getTime()),您会发现不可能从localStorage检索现有项目,因为它们的键将每毫秒更改一次,而不是一次-每天。
    • 我下面的代码通过使用toISOString() 来获得一个完整 ISO 8601 日期+时间字符串(形式为yyyy-MM-dd HH:mm:sszzzand uses .substring(0,10) as a cheap-trick 来解决这个问题 -日期组件,以便返回的字符串仅包含日期信息(位于 function getDateOnlyString 中)。
  • 下面的代码中有相当多的重复性(例如,loadTodosloadCalendar 函数几乎相同,备用它们使用的 localStorage 键值,因此可以在不重复逻辑的情况下重写. 这是留给读者的练习。

【讨论】:

  • 谢谢戴!我试过了,但得到了这个“未捕获的引用错误:未定义 KEY_TODOS”。
  • @MirandaNilhag 这是一个错字。我现在已经修好了,但我希望你能自己解决这个问题。
猜你喜欢
  • 1970-01-01
  • 2012-09-21
  • 2018-11-05
  • 2016-04-29
  • 2015-06-20
  • 2021-12-06
  • 2014-07-07
  • 2018-11-20
  • 2017-09-22
相关资源
最近更新 更多