javascript - 受javascript影响后如何恢复到原来的DOM

标签 javascript php jquery dom

想象一下,我有一个已加载的 HTML 页面,该页面已经受到初始化时添加/删除动态元素或向元素添加新类/属性/id 的 JavaScript 的影响(例如:原始源代码 [html] 标签在 javascript 加载后没有类) [html] 标签有 class="no-responsive 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/

相关文章:

php - PHP header 和 Javascript window.location 有什么区别?

javascript - 分别隐藏/显示具有相同类名的元素

jquery - 有没有办法让我的类覆盖 jQuery 主题的类?

javascript - AngularJS - 如何访问对象中的数组以在 ng-bind 中使用

javascript - Firebase - 检查使用 Google 帐户创建的用户是否正在注册或登录?

javascript - 使用类名生成样式属性

php - htaccess RewriteRule url 友好搜索

javascript - 在 Angular 中使用 Rxjs 更新来自不同 Json 源的 Json 中的数据

javascript - 点击打印页面后,CSS 与实际页面不同

javascript - 如何在成功 block 之外使用ajax函数的值