首页 > 解决方案 > 在 chrome 扩展中使用内容脚本插入 DOM 元素

问题描述

我正在尝试为 twitter 做一个扩展,我被困在本节中插入 div 块(有点像 btn) 我要添加保存 btn 的 Twitter 栏

清单.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/*"]
        }
    ]
}  

内容.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");

我研究了一些像MutationObserver这样的东西, 但在这里我得到了错误,因为参数不是节点

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

Twitter在向下滚动时删除以前的帖子添加新帖子,并在滚动回顶部时添加以前的帖子删除新帖子

标签: javascriptgoogle-chrome-extensionmutation-observerschrome-extension-manifest-v3

解决方案


对于 Twitter,MutationObserver 是必经之路,关于如何使用它,我更喜欢这个 Mozilla 指南

要让 get 正常工作,请注意语法:这里在注册 MutationObserver 时,它说监视整个主体和后代,并appendCustomNode在发生更改时调用函数。

// 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});

下一步是定义这个函数appendCustomNode

在计划如何将节点附加到卡片时,有必要考虑到您可能会多次看到同一个节点,这需要一个策略来仅附加一次自定义元素。选择一些足够随机的值,然后用该值标记所有以前看到的节点,将有助于实现这一点。这是一个例子:

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);
     }
  }
}

最后实现将要添加到卡片的按钮附加到卡片的逻辑。这里的 card 属性表示一个时间轴项的 DOM 节点。

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);
}

出于几个原因,我将保留最后一部分:当决定如何在卡片中找到按钮行时,如果使用类作为选择器,如果类发生更改,则实现会中断,这是您无法控制的。在扩展 3rd 方 Web 应用程序时,这始终是一个挑战。我建议尝试找到一个更可靠的选择器(这就是我之前使用标签名称文章来选择卡片的原因)。其次,按钮/卡片结构会定期更改,因此要考虑的另一点是:您要在哪里插入此自定义节点。最后,这种方法不需要 jQuery。


推荐阅读