想象一下,我有一个加载的HTML页面,该页面在初始化时已经受到javascript向元素添加/删除动态元素或新类/属性/ id的影响(例如:在javascript加载[html]之后,原始源代码[html]标签没有类)标签具有class =“ no-response full-with”)。想象一下之后,我手动(通过我的应用程序)添加/修改了一些ID值。想象一下,我需要能够将原始源代码(没有任何修改)保存在数据库中,但是要具有我手动添加的id属性。
基本上,我需要将给定的id属性添加到通过PHP加载的HTML源代码中的元素中。
你们对如何做这样的事情有想法吗?
最佳答案
这里没有简单的解决方案。复杂解决方案的确切性质将由您的全部要求决定。
更新概念
您已经说过,除了更改内容之外,还需要添加元素并删除它们。因此,您不能将更改的元素纯粹地(例如,通过子索引)与原始元素相关联,因为这些元素可能会更改。
所以这是我可能的处理方式:
页面加载后,立即进行任何修改,然后为每个元素赋予唯一标识符。使用jQuery确实很容易(没有它就不是特别困难):
var uniqueId = 0;
$("*").attr("data-uid", function() {
return ++uniqueId;
});
现在页面上的每个元素都有一个唯一的标识符。接下来,复制DOM并为其获取jQuery包装器:
var clone = $("html").clone();
现在,您已经有了一种可靠的方式,可以通过唯一ID将DOM中的元素与其原始版本(我们的克隆)相关联。允许用户进行更改。
当您准备找出进行了哪些更改时,请执行以下操作:
// Look for changes
clone.find("*").addBack().each(function() {
// Get this clone's unique identifier
var uid = $(this).attr("data-uid");
// Get the real element corresponding to it, if it's
// still there
var elm = $("[data-uid=" + uid + "]")[0];
// Look for changes
if (!elm) {
// This element was removed
}
else {
if (elm.id !== this.id) {
// This element's id changed
}
if (elm.className !== this.className) {
// This element's className changed
}
// ...and so on...
}
});
这将告诉您有关删除和更改的元素。如果您还想查找添加的元素,请执行以下操作:
var added = $(":not([data-uid])");
...因为它们没有属性。
您可以使用
clone
中的信息来重构原始DOM的字符串:clone.find("[data-uid]").addBack().removeAttr("data-uid");
var stringToSend = clone[0].outerHTML;
(
outerHTML
受任何模糊的现代浏览器支持,最新添加的版本是v11中的Firefox。)...当然还有上面记录变更的信息。
Live proof of concept
HTML:
<p class="content">Some content</p>
<p class="content">Some further content</p>
<p>Final content</p>
<input type="button" id="makeChange" value="Make Change">
<input type="button" id="seeResults" value="See Results">
JavaScript:
// Probably unnecessary, but I wanted a scoping
// function anyway, so we'll give the parser time
// to completely finish up.
setTimeout(function() {
// Assign unique identifer to every element
var uniqueId = 0;
$("*").attr("data-uid", function() {
return ++uniqueId;
});
// Clone the whole thing, get a jQuery object for it
var clone = $("html").clone();
// Allow changes
$("#makeChange").click(function() {
this.disabled = true;
$("p:eq(1)").attr("id", "p1");
$("p:eq(2)").addClass("foo");
alert("Change made, set an id on one element and added a class to another");
});
// See results
$("#seeResults").click(function() {
this.disabled = true;
// Look for changes
clone.find("*").addBack().each(function() {
// Get this clone's unique identifier
var uid = $(this).attr("data-uid");
// Get the real element corresponding to it, if it's
// still there
var elm = $("[data-uid=" + uid + "]")[0];
// Look for changes
if (!elm) {
display("Element with uid " + uid + ": Was removed");
}
else {
if (elm.id !== this.id) {
display("Element with uid " + uid + ": <code>id</code> changed, now '" + elm.id + "', was '" + this.id + "'");
}
if (elm.className !== this.className) {
display("Element with uid " + uid + ": <code>className</code> changed, now '" + elm.className + "', was '" + this.className + "'");
}
}
});
});
function display(msg) {
$("<p>").html(String(msg)).appendTo(document.body);
}
}, 0);
较早的答案
假设服务器每次被询问时都为页面提供相同的文本,则可以通过ajax在客户端获得未更改的文本。剩下的问题是如何将
id
属性应用于它。如果您需要原始内容,但不一定需要相同的来源(例如,标记名称更改大小写[
div
可能变为DIV
]或属性在其周围加上/丢失引号也可以),则可以使用服务器上的来源(通过ajax检索)以填充文档片段,并将id
值应用于片段,同时将其应用于主文档。然后将片段的源发送到服务器。用服务器中的完整HTML填充片段并不是那么容易。假设
html
上没有任何类或任何东西,则:var frag, html, prefix, suffix;
frag = document.createDocumentFragment();
html = document.createElement("html");
frag.appendChild(html);
prefix = stringFromServer..match(/(^.*<html[^>]*>)/);
prefix = prefix ? prefix[1] : "<!doctype html><html>";
suffix = stringFromServer.match(/(<\/html>\s*$)/);
suffix = suffix ? suffix[1] : "</html>";
html.innerHTML = stringFromServer.replace(/^.*<html[^>]*>/, '').replace(/<\/html>\s*$/, '');
在那里,我们获取服务器的字符串,获取最外层的HTML部分(或使用默认值),然后将内部HTML分配给片段内的
html
元素(尽管我考虑的越多,对需求的了解就越少完全是一个片段-您可能只需删除片段部分)。 (旁注:上面正则表达式中标识html
元素<html[^>]*>
的开始标记的部分是那些“足够好”的东西之一。它并不完美,特别是如果您将在带引号的属性值中有一个>
,例如:<html data-foo="I have a > in me">
,这是完全有效的,要解决此问题需要更费劲的解析,因此,我在上面假设您不这样做,因为这很不常见。 )然后,您可以通过
html.querySelector
和html.querySelectorAll
在其中找到元素,以便将id
属性应用于它们。形成相关的选择器会很有趣,可能会涉及很多位置信息。完成后,取回HTML发送给服务器,如下所示:
var stringToSend = prefix + html.innerHTML + suffix;
关于javascript - 受JavaScript影响后,如何返回原始DOM,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/24671258/