为啥在浏览器中调用和显示时存储在 localStorage 中的 HTML 会发生变化?

Posted

技术标签:

【中文标题】为啥在浏览器中调用和显示时存储在 localStorage 中的 HTML 会发生变化?【英文标题】:Why does HTML stored in localStorage change when recalled and displayed in the browser?为什么在浏览器中调用和显示时存储在 localStorage 中的 HTML 会发生变化? 【发布时间】:2020-11-25 04:53:14 【问题描述】:

抱歉,如果之前有人问过这个问题,我已经搜索过但找不到任何相关的内容...

我在这里有一个非常简单的网站,它有 3 个按钮:

    添加组件

    保存当前状态

    恢复保存状态

添加组件按钮正是我想要的,即在 <div data-role="collapsible-set" class="flow" id="collapsibleComponent"></div> 标签。

另外,保存当前状态 storeCurrentState(); 按钮似乎捕获了所需的代码完全相同到正在显示的内容(这是正确的)。

但是,当我点击Restore Saved State按钮(运行restorePriorState();方法)时,从localStorage读取并放回页面的代码与得救了。结果,我最终得到了一个嵌套的折叠项,如下所示...

<!DOCTYPE html>
<html>
    <head>
        <meta charset="utf-8" />
        <title>TutorialW3a</title>
        <link href="jquery-mobile/jquery.mobile.theme-1.3.0.min.css" rel="stylesheet" type="text/css" />
        <link href="jquery-mobile/jquery.mobile.structure-1.3.0.min.css" rel="stylesheet" type="text/css" />
        <script src="jquery-mobile/jquery-1.11.1.min.js"></script>
        <script src="jquery-mobile/jquery.mobile-1.3.0.min.js"></script>
    </head>
    <body>
        <div data-role="page" id="page">
            <div data-role="header">
                <h1>Header</h1>
            </div>
            <div data-role="content">
                <div data-role="collapsible-set" class="flow" id="collapsibleComponent">
                    <!--New collapsible divs go here-->
                </div>
            </div>
            <button onclick="addCollapsibleComponent()">Add component</button>
            <button onclick="storeCurrentState()">Save current state</button>
            <button onclick="restorePriorState()">Restore saved state</button>
            <div data-role="footer" data-position="fixed">
                <h4>Footer</h4>
            </div>
        </div>
    </body>
</html>
<script>
    //
    var collapsibleComponentContent = document.getElementById("collapsibleComponent");
    var collapsibleDiv;
    function addCollapsibleComponent() 
        //create div element
        collapsibleDiv = $('<div id="new" data-role="collapsible" data-collapsed="true"><h3>Heading</h3><p>Paragraph</p></div>"');
        //append new collapsible div to #collapsibleComponent
        $("#collapsibleComponent").append(collapsibleDiv);
        //collapse all collapsible divs
        $('div[data-role="collapsible"]').collapsible();
    
    //
    function storeCurrentState() 
        collapsibleDiv = document.getElementById("new");
        localStorage.setItem("html_data", JSON.stringify(collapsibleComponentContent.innerHTML));
    
    //
    function restorePriorState() 
        collapsibleComponentContent.innerHTML = JSON.parse(localStorage.getItem("html_data"));
        $("#new").collapsible();
    
</script>

这是在创建新的可折叠组件时生成的...

<div id="new" data-role="collapsible" data-collapsed="true" class="ui-collapsible ui-collapsible-inset ui-collapsible-collapsed">
<h3 class="ui-collapsible-heading ui-collapsible-heading-collapsed">
    <a href="#" class="ui-collapsible-heading-toggle ui-btn ui-btn-icon-left ui-btn-up-c" data-corners="false" data-shadow="false" data-iconshadow="true" data-wrapperels="span" data-icon="plus" data-iconpos="left" data-theme="c"
        ><span class="ui-btn-inner"
            ><span class="ui-btn-text">Heading<span class="ui-collapsible-heading-status"> click to expand contents</span></span
            ><span class="ui-icon ui-icon-plus ui-icon-shadow">&nbsp;</span></span
        ></a
    >
</h3>
<div class="ui-collapsible-content ui-collapsible-content-collapsed" aria-hidden="true"><p>Paragraph</p></div>

这就是我重新加载时创建的...

<h3 class="ui-collapsible-heading ui-collapsible-heading-collapsed">
<a href="#" class="ui-collapsible-heading-toggle ui-btn ui-btn-icon-left ui-btn-up-c" data-corners="false" data-shadow="false" data-iconshadow="true" data-wrapperels="span" data-icon="plus" data-iconpos="left" data-theme="c"
    ><span class="ui-btn-inner"
        ><span class="ui-btn-text"
            ><a href="#" class="ui-collapsible-heading-toggle ui-btn ui-btn-icon-left ui-btn-up-c" data-corners="false" data-shadow="false" data-iconshadow="true" data-wrapperels="span" data-icon="plus" data-iconpos="left" data-theme="c"
                ><span class="ui-btn-inner"
                    ><span class="ui-btn-text">Heading<span class="ui-collapsible-heading-status"> click to expand contents</span></span
                    ><span class="ui-icon ui-icon-plus ui-icon-shadow">&nbsp;</span></span
                ></a
            ><span class="ui-collapsible-heading-status"> click to expand contents</span></span
        ><span class="ui-icon ui-icon-plus ui-icon-shadow">&nbsp;</span></span
    ></a
>

【问题讨论】:

不一致是什么意思?恢复到已保存的数据时,您会得到完全不同的数据? 是的,它添加了以前没有的跨度并将其他类添加到 div 标签。 @AlwaysHelping 我已经编辑了我的原始帖子以显示生成和保存的代码,然后从本地存储重新加载更改后显示的内容 我无法重现此问题。对我来说一切似乎都很好。 多么令人困惑?,我最终看起来像i.stack.imgur.com/BU7iM.png 中所示的所有嵌套 【参考方案1】:

你在问“为什么”,所以这是答案:

JQM 是一个混合的 JS/CSS 框架,即 widgets 由 JS 增强并由 CSS 样式化。页面初始化后,框架通过添加一些嵌套元素(divspan)、pseudo-elements(图标)和事件处理程序来增强小部件(由“data-role”标签标识)。

也就是说,在您的代码中,您将初始标记的增强版本与data-role属性一起保存,但您只保存标记,这意味着您不会保存 JS data,它将在小部件初始化期间由框架创建。简而言之,您只节省了已经增强的小部件的一半。

下一次,框架将再次找到data-role 属性,但找不到关联的data 对象,通过调用$("#new").collapsible();,您最终会得到该双重嵌套标记。

更多信息:

你可以看一下JQM小部件对象如下:

$.data(document.getElementById("new"),"mobile-collapsible")

或:

$("#new").jqmData("mobile-collapsible")

您的任务有不止一种可能的解决方案。

也许您可以恢复最初的未增强标记:

$("#collapsibleComponent :jqmData(role='collapsible')").collapsible("destroy");

并保存:

localStorage.setItem("html_data", JSON.stringify($("#collapsibleComponent").html()));

最后,你假设

以与显示的内容相同的方式捕获所需的代码是正确的

错了。

【讨论】:

非常感谢您的详细解释!这是一个完美的答案,因为它给了我一些我需要了解更多的明确定义的领域......谢谢你指出我正确的方向? @Nathan:感谢您的反馈!要从社区获得更多帮助,您可能需要切换到最新的 JQM 版本 1.4.5

以上是关于为啥在浏览器中调用和显示时存储在 localStorage 中的 HTML 会发生变化?的主要内容,如果未能解决你的问题,请参考以下文章

JS惰性删除和定时删除可过期的localStorage缓存,或sessionStorage缓存

JS惰性删除和定时删除可过期的localStorage缓存,或sessionStorage缓存

刷新浏览器后显示 localStorage 中的收藏项 - Next.js 和 Typescript 项目

如何在javascript中检测浏览器选项卡是不是关闭或浏览器窗口

基于微服务的环境中的 Keycloak 身份验证流程

H5 客户端存储(Web Storage)