Deleting DOM elements before the Page is displayed to the screen (in a Chrome extension)

让人想犯罪 __ 提交于 2019-12-30 00:40:10

问题


I am trying to create an extension that will get rid of certain Page elements (by id or class) before the page is displayed to the screen. I've tried using an event listener on the document with "DOMContentLoaded" as the event but the javascript seems to execute after the page is displayed to the user and then deletes it so it's not as smooth as I want (not showing the unwanted content at all)

document.addEventListener("DOMContentLoaded", function() {

var elements = document.getElementsByClassName("header-nav-item");
while(elements.length > 0){
    elements[0].parentNode.removeChild(elements[0]);
}

var element = document.getElementById("topchapter");
element.parentNode.removeChild(element);
element = document.getElementById("wrapper_header");
    element.parentNode.removeChild(element);

});

This is the content script that my extension uses which deletes after the page is loaded. What do I need to use to modify the DOM before the pages is seen by the user?


回答1:


Use MutationObserver in the content script injected at document-start to actually delete the HTML elements from DOM during page load before they are rendered so that there's no flickering.

  • manifest.json:

    {
        "name": "Delete elements",
        "version": "1.0",
        "content_scripts": [
            {
                "matches": ["http://somesite.com/*"],
                "run_at": "document_start",
                "all_frames": true,
                "js": ["content.js"]
            }
        ],
        "manifest_version": 2
    }
    
  • content.js:

    deleteElements('.header-nav-item, #topchapter, #wrapper_header');
    
    function deleteElements(selector) {
        // in case the content script was injected after the page is partially loaded
        doDelete(document.querySelectorAll(selector));
    
        var mo = new MutationObserver(process);
        mo.observe(document, {subtree:true, childList:true});
        document.addEventListener('DOMContentLoaded', function() { mo.disconnect() });
    
        function process(mutations) {
            for (var i = 0; i < mutations.length; i++) {
                var nodes = mutations[i].addedNodes;
                for (var j = 0; j < nodes.length; j++) {
                    var n = nodes[j];
                    if (n.nodeType != 1) // only process Node.ELEMENT_NODE
                        continue;
                    doDelete(n.matches(selector) ? [n] : n.querySelectorAll(selector));
                }
            }
        }
        function doDelete(nodes) {
            [].forEach.call(nodes, function(node) { node.remove() });
        }
    }
    
    // Chrome pre-34
    if (!Element.prototype.matches)
        Element.prototype.matches = Element.prototype.webkitMatchesSelector;
    

Notes:

  • The observer callback must be simple and fast in order not to introduce lags during page loading so a plain for loop is better than forEach callbacks.
  • When the job is done it's best to disconnect the observer immediately so that the rest of the page isn't needlessly observed.
  • Don't add multiple observers, incorporate all checks in just one
  • mutations array also contains text subnodes along with the added elements themselves. That's why we check if nodeType is Node.ELEMENT_NODE which equals 1.
  • Each mutation's addedNodes array usually has container elements like DIV, for example, which in turn may have an element we want to delete inside. So we have to examine it with querySelector or querySelectorAll.
  • childNode.remove() works since Chrome 23


来源:https://stackoverflow.com/questions/32533580/deleting-dom-elements-before-the-page-is-displayed-to-the-screen-in-a-chrome-ex

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!