简体   繁体   中英

Inserting DOM elements using content script in chrome extension

I'm trying to make an extension for twitter and I'm stuck at inserting the div block (Kinda like btn) in this section 我想在其中添加保存 btn 的 Twitter 栏

Manifest.json

{
    "manifest_version": 3,
    "name": "Twitter Saver",
    "version": "0.0.1",
    "description": "Twitter Saver| Save tweets.",
    "permissions": ["tabs", "https://*.twitter.com/*"],
    "icons": {
        "128": "img/icon-app-128.png",
        "256": "img/icon-app-128@2x.png"
    },
    "content_scripts": [
        {
            "html": ["save-dropdown.html"],
            "js": ["js/jquery-3.6.0.min.js", "js/content.js"],
            "matches": ["https://*.twitter.com/*"]
        }
    ]
}  

Content.js

$(
        "<div>",{
            class: "css-1dbjc4n r-18u37iz r-1h0z5md",
            text: "HELLO WORLD"
        }
    ).appendTo(".css-1dbjc4n.r-1ta3fxp.r-18u37iz.r-1wtj0ep.r-1s2bzr4.r-1mdbhws");

I've looked into few things like MutationObserver but here I got error as parameter is not a node

let react_root = $("#react-root");
let callback = function(changeList, observer) => {
         console.log(changeList);
}
const observer = new MutationObserver();
observer.observe(callback, {childList: true});

Twitter removes the previous posts as scrolling down adding new ones and adds the previous ones removing new ones when scrolling back to top

For Twitter, MutationObserver is the way to go, and for how to use it, I prefer this Mozilla guide .

To get is working correctly, note the syntax: here in registering the MutationObserver, it says watch the entire body and descendants, and call function appendCustomNode when change occurs.

// Step 1. Create an observer instance linked to the callback function
// const observer = new MutationObserver(callback);
// Step 2. Start observing the target node for configured mutations
// observer.observe(targetNode, config);

const observer = new MutationObserver(appendCustomNode); 
observer.observe(document.body, {subtree: true, childList: true});

Next step is to define this function appendCustomNode .

In planning how to append nodes to the cards, it is necessary to take into consideration that you will see the same node possibly multiple times, which requires having a strategy to append the custom element only once. Picking some sufficiently random value, then tagging all previously seen nodes with that value, will help accomplish this. Here is an example:

const customTag = `tag-${Date.now()}` // your choice of a valid & unique value

function appendCustomNode(){

  // find all timeline cards, their tag name is article
  const cards = document.getElementsByTagName('article');

  // check each card
  for (let n = 0; n < cards.length; n++) {

     const card = cards[n];

     // check that cards is new / has not been seen before
     if (!card.hasAttribute(customTag)) { 

       addButton(card);

       // mark the card as "processed" by adding the custom tag
       card.setAttribute(customTag, true);
     }
  }
}

Lastly implement the logic to append the button you want to add to the card. Here card attribute represents the DOM node of one timeline item.

function addButton(card){

   const myButton = document.createElement('div');
   myButton.innerText = 'hello world';

   // select the div of action buttons
   // or wherever you want to insert your custom node 
   // SEE NOTE BELOW
   const target = card.querySelector('....?....')

   // append/prepend/insertAdjacentHTML the button here
   target.append(myButton);
}

I will leave this last part open for a few reasons: when deciding how to find the buttons row in the card, if using classes as a selector, the implementation breaks if the classes change, which is out of your control. This is always a challenge when extending 3rd party web apps. I suggest trying to find a more reliable selector (which is why earlier I used tag name article to select cards). Secondly the buttons/card structure changes periodically, so that is another point to consider: where do you want to insert this custom node. Lastly this approach does not require jQuery.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM