You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Chrome扩展开发:打开新标签并滚动至指定位置(仅作用于目标标签)

问题描述

我想要开发一款Chrome扩展,用于记录当前页面的URL和滚动坐标,以便后续继续阅读。我使用chrome.tabs.create在新标签中打开目标URL,但卡在页面滚动步骤。我尝试通过chrome.tabs.onUpdated.addListener和chrome.scripting.executeScript注入JavaScript命令,但不知道如何仅对特定标签执行脚本(当前方法会作用于所有新打开的标签)。

现有代码

manifest.json

{
    "manifest_version": 3,
    "name": "Relay Reader",
    "version": "1.0",
    "permissions": ["contextMenus", "activeTab", "tabs", "webRequest", "scripting"],
    "action": {
        "default_popup": "popup.html"
    },
    "description": "Continue reading where you are interrupted",
    "icons": {
        "16": "images/icon-16.png",
        "32": "images/icon-32.png",
        "48": "images/icon-48.png",
        "128": "images/icon-128.png"
    },
    "content_scripts": [
        {
          "js": ["scripts/content.js"],
          "matches": ["http://*/*", "https://*/*"]
        }
    ],
    "background": {
        "service_worker": "./scripts/background.js"
    },
    "host_permissions": [
        "https://*/*", "http://*/*"
    ]
}

background.js

chrome.runtime.onInstalled.addListener((tableId, changeInfo, tab) => {
    chrome.contextMenus.create({
        id: 'addMark',
        title: "Bookmark Here",
        contexts: ['all']
    })
});

chrome.tabs.onUpdated.addListener((tabId, changeInfo, tab) => {
    if (changeInfo.status == "complete") {
        chrome.scripting.executeScript({
            target: {tabId: tabId},
            func: () => {window.scrollTo(0, 400)}
        });
    }
})

function addMark(info, tab) {
    if (info.menuItemId == "addMark") {
        chrome.tabs.sendMessage(tab.id, { action: "getSiteInfo" }, (response) => {
            let {siteUrl: url, position: top} = response;
            chrome.tabs.create({url: "example.com"}, () => {})
        })
    }
}

chrome.contextMenus.onClicked.addListener(addMark);

content.js

chrome.runtime.onMessage.addListener((request, sender, sendResponse) => {
    if (request.action == "getSiteInfo") {
        let top = window.scrollY;
        let url = window.location.href;
        
        sendResponse({siteUrl: url, position: top});
    }
})
解决方案

问题出在全局的chrome.tabs.onUpdated监听会对所有标签生效。我们可以通过记录自己创建的标签ID,仅对该标签执行滚动逻辑,或者直接在chrome.tabs.create的回调中等待标签加载完成后执行脚本。

方法一:在tabs.create回调中绑定临时监听

修改background.js中的addMark函数,创建标签后添加针对该标签的临时监听,执行滚动后立即移除:

function addMark(info, tab) {
    if (info.menuItemId == "addMark") {
        chrome.tabs.sendMessage(tab.id, { action: "getSiteInfo" }, (response) => {
            const {siteUrl: url, position: top} = response;
            // 创建目标标签
            chrome.tabs.create({url: url}, (newTab) => {
                // 定义临时监听函数
                const scrollToPosition = (tabId, changeInfo) => {
                    if (tabId === newTab.id && changeInfo.status === "complete") {
                        chrome.scripting.executeScript({
                            target: {tabId: tabId},
                            func: (scrollTop) => window.scrollTo(0, scrollTop),
                            args: [top] // 传递记录的滚动位置
                        });
                        // 执行后移除监听,避免影响其他标签
                        chrome.tabs.onUpdated.removeListener(scrollToPosition);
                    }
                };
                // 添加监听
                chrome.tabs.onUpdated.addListener(scrollToPosition);
            });
        })
    }
}

同时删除原来全局的chrome.tabs.onUpdated监听代码,避免冲突。

方法二:维护待滚动标签列表(适合批量场景)

如果需要处理多个标记,可以维护一个存储标签ID和对应滚动位置的Map,在全局监听中判断并执行:

// 存储需要滚动的标签ID与对应位置
const pendingScrolls = new Map();

function addMark(info, tab) {
    if (info.menuItemId == "addMark") {
        chrome.tabs.sendMessage(tab.id, { action: "getSiteInfo" }, (response) => {
            const {siteUrl: url, position: top} = response;
            chrome.tabs.create({url: url}, (newTab) => {
                // 将标签ID和滚动位置存入Map
                pendingScrolls.set(newTab.id, top);
            });
        })
    }
}

chrome.tabs.onUpdated.addListener((tabId, changeInfo) => {
    if (changeInfo.status === "complete" && pendingScrolls.has(tabId)) {
        const scrollTop = pendingScrolls.get(tabId);
        chrome.scripting.executeScript({
            target: {tabId: tabId},
            func: (top) => window.scrollTo(0, top),
            args: [scrollTop]
        });
        // 执行后从Map中移除
        pendingScrolls.delete(tabId);
    }
})

关键说明

  • 两种方法都避免了全局监听对所有标签的影响,仅针对我们创建的目标标签执行滚动。
  • 使用args参数传递记录的滚动位置,替代硬编码的400,实现动态滚动到上次阅读位置。
  • 方法一的临时监听更轻量化,执行后立即销毁;方法二适合需要同时处理多个标签的场景。

内容的提问来源于stack exchange,提问作者Ma Twickenham

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.31 18:45:20