【问题标题】:How to update an HTML string with an element from DOM如何使用 DOM 中的元素更新 HTML 字符串
【发布时间】:2021-05-18 03:24:33
【问题描述】:

我正在尝试使用 DOM 中的元素更新字符串化 HTML 元素。 此字符串化 HTML 元素位于 localStorage 的数组中。

首先,这是我将其转换为可操作的 HTML 的方法:

let toBeUpdated = document.createElement('div');
toBeUpdated.innerHTML = `${var_stringify_html_from_localstorage}`;
toBeUpdated = toBeUpdated.firstElementChild;

这个toBeUpdated 元素是一个div,其中包含一个id 为updateMe 的元素。 我想用来自 DOM 的元素更新这个“虚拟”(不可见)#updateMe 元素。

我先试了:

let updateme = toBeUpdated.querySelector("#updateMe");
let updateme_DOM = document.querySelector("#updateMe");

toBeUpdated.replaceChild(updateme, updateme_DOM);

返回Uncaught DOMException: Node.replaceChild: Child to be replaced is not a child of this node

其次我尝试了:

let updateme = toBeUpdated.querySelector("#updateMe");
let updateme_DOM = document.querySelector("#updateMe");

updateme.replaceWith(updateme_DOM);

这会从 DOM 中删除原始的 #updateMe 并且不会更新 toBeUpdated 元素。

我显然错过了什么,但我看不到什么......

我试图尽可能地重现我的情况:

//initial state of local storage
let motd = ["<div id='toBeUpdated'><h1>Hello World</h1><p id='updateMe'>Message of tomorrow</p></div>"];
window.localStorage.setItem('motds', JSON.stringify(motd));

// My situation, later in the code
let motds = JSON.parse(window.localStorage.getItem('motds'));
let toBeUpdated = document.createElement('div');
toBeUpdated.innerHTML = `${motds[0]}`;
toBeUpdated = toBeUpdated.firstElementChild; // this is the div#toBeUpdated

let DOMUpdateMe = document.getElementById('updateMe');
let storageUpdateMe = toBeUpdated.querySelector("#updateMe"); // getElementById doesn't work here

// Replace
storageUpdateMe.replaceWith(DOMUpdateMe);

// Back in local storage
motds[0] = toBeUpdated.outerHTML;
window.localStorage.setItem('motds', JSON.stringify(motds));
<body>
  <div id="toBeUpdated">
    <h1>Hello World</h1>
    <p id="updateMe">Message of tomorrow</p>
  </div>
</body>

【问题讨论】:

  • updateme.replaceWith(updateme_DOM); 不应该与updateme_DOM.replaceWith(updateme);相反
  • 感谢@Breezer,但我想要更新我的“虚拟”(不是真正在 DOM 中)元素,而不是用户看到的 DOM

标签: javascript html local-storage


【解决方案1】:

您似乎唯一缺少的是在将 DOM 节点插入非 DOM 之前对其进行克隆。

这是您的代码的分步复制,仅更改此内容,它有效。为了清楚起见,我还将localStorage 的初始状态设置为“今天的消息”。

localStorage 是用变量模拟的,因为它会由于 CORS 触发 sn-p 内部的安全错误

//initial state of local storage
let motd = ["<div id='toBeUpdated'><h1>Hello World</h1><p id='updateMe'>Message of today</p></div>"];
//window.localStorage.setItem('motds', JSON.stringify(motd));

//Read from local storage
//let motds = JSON.parse(window.localStorage.getItem('motds'));
const motds = JSON.parse(JSON.stringify(motd)); //Simulate local storage
console.log("In storage:", motds);

//Create element outside of DOM
const toBeUpdated = document.createElement('div');
toBeUpdated.innerHTML = motds[0];
console.log("To be updated:", toBeUpdated.outerHTML);

//Get part to update
const DOMUpdateMe = document.getElementById('updateMe');
const storageUpdateMe = toBeUpdated.querySelector("#updateMe");
console.log(DOMUpdateMe, storageUpdateMe);
//Replace part outside of DOM with clone of part from DOM
storageUpdateMe.replaceWith(DOMUpdateMe.cloneNode(true));
console.log(toBeUpdated.outerHTML);

//Store back
motds[0] = toBeUpdated.outerHTML;
motd = JSON.stringify(motds); //Simulate local storage
console.log(motd);
//window.localStorage.setItem('motds', JSON.stringify(motds));
<body>
  <div id="toBeUpdated">
    <h1>Hello World</h1>
    <p id="updateMe">Message of tomorrow</p>
  </div>
</body>

【讨论】:

  • 你是救生员。还有奖金,你纠正了我的例子。真的非常感谢,我永远找不到.cloneNode(true) 方法。
【解决方案2】:

它使用firstChild 而不是firstElementChild 工作

let toBeUpdated = document.createElement('div');
//toBeUpdated.innerHTML = `${var_stringify_html_from_localstorage}`;
toBeUpdated.innerHTML = `<div id="updateMe">New DIV</div>`;
let updateme = document.getElementById('updateMe')
updateme.replaceWith(toBeUpdated.firstChild);
&lt;div id='updateMe'&gt;Old DIV&lt;/div&gt;

【讨论】:

  • 感谢@Kinglish,但我尝试反过来存档,请参阅我更新的帖子。语言环境存储中的变量实际上是在这里缓存我想要更新的元素列表(不想更新 DOM)
【解决方案3】:

您不应该使用简单的newUpdateMe = DOMUpdateMe;

//initial state of local storage
let motd = ["<p class='updateMe'>Message of the day<p>"];
window.localStorage.setItem('motds', JSON.stringify(motd));

// My situation, later in the code
let motds = JSON.parse(window.localStorage.getItem('motds'));
let dOMUpdateMe = document.querySelectorAll('#toBeUpdated > *');

let counter = 0;
dOMUpdateMe.forEach(function(dOMToUpdate) {
  console.log(dOMToUpdate);
  if(dOMToUpdate.classList.contains('updateMe')) {
    motds[counter] = dOMToUpdate.outerHTML;
    counter++;
  }
})
window.localStorage.setItem('motds', JSON.stringify(motds));
<div id="toBeUpdated">
  <h1 class="updateMe">Hello World</h1>
  <p class="updateMe">Update Me</p>
  <p class="no">No not Update Me</p>
  <p class="no">No not Update Me</p>
  <p class="no">No not Update Me</p>
  <p class="updateMe">Update Me too</p>
  <p class="no">No not Update Me</p>
</div>

【讨论】:

  • 你说得对,这就是我最先做的,它奏效了。但是#toBeUpdated 内容是动态的(某些元素只在特定条件下显示),所以我只想更新这个始终可见但它的值可能会改变的#updateMe 元素(我网站中的实际元素是投票的​​比率/down-vote,以及一些在点击时会改变颜色并执行操作的按钮)
  • 在 localStorage 上添加项目时,是什么阻止您有条件地检查 toBeUpdated 是否可见?
  • 我只想更新#updateMe,而不更新#toBeUpdated 的其余部分。 toBeUpdated 总是可见的(它是一个帖子,就像在社交网络中一样),它有一些可能不可见的子元素。例如,用于查看 cmets 的按钮仅在提要上可见,而在实际帖子页面上不可见。我不需要更新本地存储中的整个帖子(toBeUpdated),只需要更新一些部分(上/下投票按钮,这里用#updateMe表示)
  • 你应该为 updateMe 使用一个类。我更新了答案。
  • 我更新了代码。应该更清楚。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2018-09-19
  • 1970-01-01
  • 2010-10-04
  • 2013-09-13
  • 2021-04-27
  • 2011-03-07
相关资源
最近更新 更多