1

如果您在浏览器中打开一个文本文件(.txt、.js、.css、...),它将被包裹在一个漂亮的 DOM 树中。

例如,打开这个 .txt 文件并输入

javascript:alert(document.documentElement.innerHTML);

进入您的地址栏。不错...每个主流浏览器都支持对这个包装的文本文件进行 DOM 操作,这对于编写强大的小书签或用户脚本来说是一件好事。

但是,Firefox 无法分配任何元素的 innerHTML。例如,

javascript: document.body.innerHTML = document.body.innerHTML.replace(/(\d+\s+\w+(?=\s+\d+))/g, '<span style="color:red">$1</span>'); void 0;

将适用于除 Firefox 之外的所有浏览器。

有解决此问题的技巧吗?

(不,我不想手动解析 innerHTML 字符串,不,它也不适用于 jQuery。)

4

4 回答 4

1

它失败了,因为没有body- 即使您链接的文件也只是一个没有正文的文本文件(也许您正在 firebug 中查看它?)。

最好的办法是使用正则表达式替换,因为您正在处理文本。

于 2009-04-11T14:19:05.817 回答
1

我想我找到了一个可行的解决方案。首先,让我就这个问题提供更多细节。

问题是:Firefox 创建了类似的东西

[some wrapper]
+---document
    +---<html>[=documentElement]
        +---<body>
            +---<head/>
            +---<pre>
                +---[actual plain text contents]

但包装的文档对象不支持正确设置 innerHTML。因此,基本思想是,创建一个完全支持 innerHTML 的新文档对象。以下是它的工作原理:

var setInnerHTML = function(el, string) {
    if (typeof window.supportsInnerHTML == 'undefined') {
        var testParent = document.createElement('div');
        testParent.innerHTML = '<br/>';
        window.supportsInnerHTML = (testParent.firstChild.nodeType == 1);
    }
    if (window.supportsInnerHTML) {
        el.innerHTML = string;
    } else {
        if (!window.cleanDocumentObject) {
            /* this is where we get a 'clean' document object */
            var f = document.createElement('iframe');
            f.style.setProperty('display', 'none', 'important');
            f.src = 'data:text/html,<!DOCTYPE html><html><title></title></html>';
            document.body.appendChild(f); /* <- this is where FF creates f.contentDocument */
            window.cleanDocumentObject = f.contentDocument;
            document.body.removeChild(f);
        }

        /* let browser do the parsing */
        var div = window.cleanDocumentObject.createElement('div');
        div.innerHTML = string; /* this does work */

        /* copy childNodes */
        while(el.firstChild) {
            el.removeChild(el.firstChild); /* cleanup */
        }
        for (var i = 0; i < div.childNodes.length; i++) {
            el.appendChild(div.childNodes[i].cloneNode(true));
        }
        delete div;
    }
}

编辑:

这个版本更好更快;使用 XSLTProcessor 而不是 iFrame。

var setInnerHTML = function(el, string) {
    // element.innerHTML does not work on plain text files in FF; this restriction is similar to
    // http://groups.google.com/group/mozilla.dev.extensions/t/55662db3ea44a198
    var self = arguments.callee;
    if (typeof self.supportsInnerHTML == 'undefined') {
        var testParent = document.createElement('div');
        testParent.innerHTML = '<p/>';
        self.supportsInnerHTML = (testParent.firstChild.nodeType == 1);
    }
    if (self.supportsInnerHTML) {
        el.innerHTML = string;
        return el;
    } else if (typeof XSLTProcessor == 'undefined') {
        return undefined;
    } else {
        if (typeof self.cleanDocument == 'undefined')
            self.cleanDocument = createHTMLDocument();

        if (el.parentNode) {
            var cleanEl = self.cleanDocument.importNode(el, false);
            cleanEl.innerHTML = string;
            el.parentNode.replaceChild(document.adoptNode(cleanEl), el);
        } else {
            var cleanEl = self.cleanDocument.adoptNode(el);
            cleanEl.innerHTML = string;
            el = document.adoptNode(cleanEl);
        }

        return el;
    }

    function createHTMLDocument() {
        // Firefox does not support document.implementation.createHTMLDocument()
        // cf. http://www.quirksmode.org/dom/w3c_html.html#t12
        // the following is taken from http://gist.github.com/49453
        var xmlDoc = document.implementation.createDocument('', 'fooblar', null);
        var templ = '<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">'
                + '<xsl:output method="html"/><xsl:template match="/">'
                + '<html><title/><body/></html>'
                + '</xsl:template></xsl:stylesheet>';
        var proc = new XSLTProcessor();
        proc.importStylesheet(new DOMParser().parseFromString(templ,'text/xml'));
        return proc.transformToDocument(xmlDoc);
    }
};
于 2009-04-12T15:21:29.150 回答
0

使用 GreaseMonkey

于 2009-04-11T14:13:44.533 回答
0

似乎在 Firefox 3 中的文本文档上,分配任何节点的 innerHTML 就像您分配给 innerText 一样(带有“<html><body><pre>”前缀)。

(由于非 XML/HTML 文档上的 DOM 脚本是完全未定义的,这当然是 Firefox 的权利;在 HTML 页面中显示文本文件似乎是一种快速破解。)

所以你不能在 Firefox 上使用 innerHTML,但是其他 DOM 方法可以工作:

var span= createElement('span');
span.style.color= 'red';
span.appendChild(document.createTextNode(match));
于 2009-04-11T16:17:10.243 回答