Какие еще варианты замены всего HTML-документа через W3C DOM? - PullRequest
19 голосов
/ 28 ноября 2010

Мне интересно, как люди заменяют документ целиком во время выполнения в веб-приложении Ajax.Это редко, но я обнаружил несколько ситуаций, когда приложению требуется перестройка всей страницы, и все присутствует локально, без необходимости повторного использования сервера.

Я могу легко подготовить новыйдокумент как или новое дерево DOM или как строка.Поэтому я оцениваю компромиссы для различных подходов.

Если я хочу использовать подход String, это, кажется, работает:

document.open();
document.write(newStringDoc);
document.close();

Большинство браузеров делают это просто отлично, но многиеиметь небольшое мерцание при повторном рендеринге.Я заметил, что во второй раз через Firefox 4.0b7 будет просто сидеть и крутиться, как будто он загружается.Нажатие кнопки «Стоп» на панели адреса завершает визуализацию страницы.( Редактировать: это, похоже, исправлено в 4.0b8) Также этот метод, по-видимому, не позволяет пользователю нажимать кнопку обновления для перезагрузки текущего URL (он перезагружает динамически генерируемую страницу).

ЕслиЯ использую новый подход дерева DOM (который имеет различные преимущества / недостатки в гибкости и скорости), тогда это, кажется, работает:

document.replaceChild(newDomDoc, document.documentElement);

Большинство браузеров, кажется, справляются с этим прекрасно без мерцания.К сожалению, бета-версия IE9 выбрасывает «DOM Exception: HIERARCHY_REQUEST_ERR (3)» в replaceChild и никогда не завершается.Я не пробовал последнюю версию предварительного просмотра, чтобы увидеть, если это просто новая ошибка, которая была исправлена.( Редактировать: это, кажется, исправлено в RC1.)

Мой вопрос: Есть ли у кого-то другой подход, отличающийся от любого из них?У кого-нибудь есть какие-то другие предупреждения, когда, возможно, конкретный браузер не работает с одним из этих подходов?

Обновление: Возможно, это добавит контекст и поможет воображению.Рассмотрим ситуацию, когда приложение находится в автономном режиме.Нет доступных серверов для перенаправления или обновления.Необходимое состояние приложения уже загружено (или сохранено) на стороне клиента.Интерфейс пользователя построен на основе шаблонов на стороне клиента.

Я считаю, что Gmail использует фреймы, встроенные в корневой документ.Похоже, что исходный документ, по крайней мере, для некоторых из этих iframe - это просто пустой документ HTML5, которым затем манипулирует родительский документ.

Использование iframe было бы еще одним вариантом требования заменить текущий документ путем замены всего документа.дочерний элемент iframe или просто его документ.Однако существует такая же ситуация с тем, какой подход прикрепить новый документ к iframe.

1 Ответ

19 голосов
/ 02 декабря 2010

Полагаю, я отвечу на это своими собственными выводами, когда буду завершать свои исследования по этому вопросу.

Поскольку оба браузера, у которых есть проблемы с одним из этих методов, являются бета-версиями, я открылотчеты об ошибках, которые, как мы надеемся, устранят их до их полного выпуска:

Я также довольно последовательно обнаружил, что это ...

document.replaceChild(newDomDoc, document.documentElement);

... в 2-10 раз быстрее, чем этот ...

var doc = document.open("text/html");
doc.write(newStringDoc);
doc.close();

... даже с учетом времени, необходимого для сборки DOM-узлов по сравнению со сборкой HTML-строки.Это может быть причиной мерцания или просто еще одним аргументом в пользу подхода DOM.Chrome не мерцает ни одним из этих методов.

Обратите внимание на тонкое изменение в хранении возвращенного document, которое обходит ошибку в Firefox 4.0b7.

Также обратите внимание на этот добавленный тип MIME, которыйутверждение IE docs является "обязательным".

Наконец, в Internet Explorer, похоже, возникли некоторые проблемы с разрешением тегов ссылок, которые были созданы до замены нового документа. Назначение ссылки href обратно на себя, по-видимому, исправляет

// IE requires link repair
if (document.createStyleSheet) {
    var head = document.documentElement.firstChild;
    while (head && (head.tagName||"") !== "HEAD") {
        head = head.nextSibling;
    }

    if (head) {
        var link = head.firstChild;
        while (link) {
            if ((link.tagName||"") === "LINK") {
                link.href = link.href;
            }
            link = link.nextSibling;
        }
    }
}

Можно охватить все базы и объединить их следующим образом ...

var doc = document;
try {
    var newRoot = newDoc.toDOM();
    doc.replaceChild(newRoot, doc.documentElement);

    // IE requires link repair
    if (doc.createStyleSheet) {
        var head = newRoot.firstChild;
        while (head && (head.tagName||"") !== "HEAD") {
            head = head.nextSibling;
        }

        if (head) {
            var link = head.firstChild;
            while (link) {
                if ((link.tagName||"") === "LINK") {
                    link.href = link.href;
                }
                link = link.nextSibling;
            }
        }
    }
} catch (ex) {
    doc = doc.open("text/html");
    doc.write(newDoc.toString());
    doc.close();
}

... при условии, что у вас есть возможность выбрать подход какЯ делаю .

...