编程语言
首页 > 编程语言> > javascript – 在向用户显示页面之前拦截和修改DOM

javascript – 在向用户显示页面之前拦截和修改DOM

作者:互联网

我正在尝试创建一个Firefox插件(使用插件SDK)来修改页面的显示方式,主要是作为培训/学习练习.

对于某些任务(比如使用新功能扩充页面),使用pageMod非常好.页面加载,我运行一些JS来显示/隐藏/添加元素.

我的问题是:我可以在页面甚至开始显示之前对DOM执行修改(所以:服务器返回的HTML文档)吗?

例如:从服务器返回的页面是:

<html>
    <body>
        <table>
            <tr>
                <td>Item 1.1</td>
                <td>Item 1.2</td>
                <td>Item 1.3</td>
            </tr>
            <tr>
                <td>Item 2.1</td>
                <td>Item 2.2</td>
                <td>Item 2.3</td>
            </tr>
        </table>
    </body>
</html>

但我希望FF代替:

<html>
    <body>
        <ul>
            <li>Item 1.1, Item 1.2, Item 1.3</li>
            <li>Item 2.1, Item 2.2, Item 2.3</li>
        </ul>
    </body>
</html>

在页面加载后执行此操作将首先显示表格,然后它将快速“闪烁”到列表中.它可能足够快,但如果我要改变< img>标签到< a>,例如防止(不想要)图像加载,这是不够的.

我正在寻找使用contentScriptWhen:在pageMod中“start”并尝试附加监听器,但我无法看到我如何实时修改DOM'(或者事件阻止在所有页面加载之前显示任何类型的页面) ).

我已经检查了cloud-to-butt扩展,因为它确实修改了页面,但我甚至无法让它工作:当作为pageMod连接启动时代码失败:

 document.getElementById('appcontent').addEventListener('DOMContentLoaded', function(e)

因为document.getElementById(‘appcontent’)返回null.

我非常感谢一些指示:是否可能,如何附加脚本,如何拦截HTML并在经过一些修改后将其发送回去.

编辑:
好的,所以我认为我能拦截数据:

let { Ci,Cr,CC } = require('chrome');
let { on } = require('sdk/system/events');
let { newURI } = require('sdk/url/utils');
let ScriptableInputStream = CC("@mozilla.org/scriptableinputstream;1", "nsIScriptableInputStream", "init");
on('http-on-examine-response', function (event) {
    var httpChannel = event.subject.QueryInterface(Ci.nsIHttpChannel);
    var traceChannel = event.subject.QueryInterface(Ci.nsITraceableChannel);
    if (/example.com/.test(event.subject.URI.spec)) {
        traceChannel.setNewListener(new MyListener());
    }
}, true);

function MyListener(downloader) {
    this.data = "";
}

MyListener.prototype = {
    onStartRequest: function(request, ctx) {
        this.data = [];
    },

    onDataAvailable : function(request, context, inputStream, offset, count) {
        var scriptStream = new ScriptableInputStream(inputStream);
        this.data.push(scriptStream.read(count));
        scriptStream.close();
    },

    onStopRequest: function(request, ctx, status) {
        console.log(this.data.join(''));
    }
}

现在在onStopRequest中,我想对数据做一些事情并将其输出回原来的位置……

请注意,这适用于字符串而不是DOM,所以它并不完美,但它是一个开始的地方:)

EDIT2:

嗯,我得到了它的工作,虽然我有一种感觉,我不应该这样做:

onStopRequest: function(request, ctx, status) {
        //var newPage = this.data.join('');
        var newPage = "<html><body><h1>TEST!</h1></body></html>";
        var stream = converter.convertToInputStream(newPage);
        var count = {};
        converter.convertToByteArray(newPage, count);
        this.originalListener.onDataAvailable(request, ctx,
            stream, 0, count.value);

        this.originalListener.onStopRequest(request, ctx, status);
    },

解决方法:

My problem is: can I perform modification on DOM (so: the HTML document that is returned by server) before the page even starts displaying?

是的,javascript执行在第一次呈现页面之前开始. DOM Parser会通知mutation observers,因此您可以在解析器添加元素后立即删除元素.

您甚至可以在使用contentScript加载的内容脚本中注册变异观察器:“start”,因此在渲染之前,应该通知他们在添加到树中的所有元素,因为观察者通知在微任务队列中执行,而渲染发生在宏上任务队列.

but I wasn’t even able to get it to work: when attached as a pageMod on start the code failed on:
document.getElementById('appcontent').addEventListener('DOMContentLoaded', function(e)

当然.你不应该假设特别是任何元素 – 甚至不是< body>标记 – 在页面加载期间早期可用.您将不得不等待它们变得可用.

DOMContentLoaded事件可以简单地在文档对象上注册.我不知道你为什么要在某个元素上注册它.

(or event prevent any kind of page display before all page was loaded).

你并不真的想要它,因为它会增加页面加载时间,从而降低网站的响应能力.

标签:mozilla,javascript,firefox-addon,firefox-addon-sdk
来源: https://codeday.me/bug/20190925/1816541.html