คำอธิบาย
ใช้ chrome.scripting API เพื่อเรียกใช้สคริปต์ในบริบทต่างๆ
สิทธิ์
scriptingความพร้อมใช้งาน
ไฟล์ Manifest
หากต้องการใช้ chrome.scripting API ให้ประกาศสิทธิ์ "scripting" ใน Manifest รวมถึงสิทธิ์โฮสต์สำหรับหน้าเว็บที่จะแทรกสคริปต์ ใช้คีย์ "host_permissions" หรือสิทธิ์ "activeTab" ซึ่งจะให้สิทธิ์ของโฮสต์ชั่วคราว ตัวอย่างต่อไปนี้ใช้สิทธิ์ activeTab
{
"name": "Scripting Extension",
"manifest_version": 3,
"permissions": ["scripting", "activeTab"],
...
}
แนวคิดและการใช้งาน
คุณใช้ chrome.scripting API เพื่อแทรก JavaScript และ CSS ลงใน
เว็บไซต์ได้ ซึ่งคล้ายกับสิ่งที่คุณทำได้ด้วยสคริปต์เนื้อหา แต่การใช้เนมสเปซ chrome.scripting ทำให้ส่วนขยาย
ตัดสินใจได้ในขณะรันไทม์
เป้าหมายการฉีด
คุณใช้พารามิเตอร์ target เพื่อระบุเป้าหมายที่จะแทรก JavaScript หรือ CSS ได้
ช่องเดียวที่ต้องกรอกคือ tabId โดยค่าเริ่มต้น การแทรกจะทำงานใน
เฟรมหลักของแท็บที่ระบุ
function getTabId() { ... }
chrome.scripting
.executeScript({
target : {tabId : getTabId()},
files : [ "script.js" ],
})
.then(() => console.log("script injected"));
หากต้องการเรียกใช้ในเฟรมทั้งหมดของแท็บที่ระบุ คุณสามารถตั้งค่า allFrames boolean
เป็น true ได้
function getTabId() { ... }
chrome.scripting
.executeScript({
target : {tabId : getTabId(), allFrames : true},
files : [ "script.js" ],
})
.then(() => console.log("script injected in all frames"));
นอกจากนี้ คุณยังแทรกไปยังเฟรมที่เฉพาะเจาะจงของแท็บได้ด้วยการระบุรหัสเฟรมแต่ละรายการ
ดูข้อมูลเพิ่มเติมเกี่ยวกับรหัสเฟรมได้ที่ chrome.webNavigation
API
function getTabId() { ... }
chrome.scripting
.executeScript({
target : {tabId : getTabId(), frameIds : [ frameId1, frameId2 ]},
files : [ "script.js" ],
})
.then(() => console.log("script injected on target frames"));
โค้ดที่แทรก
ส่วนขยายสามารถระบุโค้ดที่จะแทรกผ่านไฟล์ภายนอกหรือตัวแปร รันไทม์
ไฟล์
ไฟล์จะระบุเป็นสตริงที่เป็นเส้นทางที่เกี่ยวข้องกับไดเรกทอรีรากของส่วนขยาย
โค้ดต่อไปนี้จะแทรกไฟล์ script.js ลงในเฟรมหลักของแท็บ
function getTabId() { ... }
chrome.scripting
.executeScript({
target : {tabId : getTabId()},
files : [ "script.js" ],
})
.then(() => console.log("injected script file"));
ฟังก์ชันรันไทม์
เมื่อแทรก JavaScript ด้วย scripting.executeScript() คุณจะระบุฟังก์ชันที่จะเรียกใช้แทนไฟล์ได้ ฟังก์ชันนี้ควรเป็นตัวแปรฟังก์ชันที่พร้อมใช้งานในบริบทของส่วนขยายปัจจุบัน
function getTabId() { ... }
function getTitle() { return document.title; }
chrome.scripting
.executeScript({
target : {tabId : getTabId()},
func : getTitle,
})
.then(() => console.log("injected a function"));
function getTabId() { ... }
function getUserColor() { ... }
function changeBackgroundColor() {
document.body.style.backgroundColor = getUserColor();
}
chrome.scripting
.executeScript({
target : {tabId : getTabId()},
func : changeBackgroundColor,
})
.then(() => console.log("injected a function"));
คุณแก้ไขปัญหานี้ได้โดยใช้พร็อพเพอร์ตี้ args ดังนี้
function getTabId() { ... }
function getUserColor() { ... }
function changeBackgroundColor(backgroundColor) {
document.body.style.backgroundColor = backgroundColor;
}
chrome.scripting
.executeScript({
target : {tabId : getTabId()},
func : changeBackgroundColor,
args : [ getUserColor() ],
})
.then(() => console.log("injected a function"));
สตริงรันไทม์
หากแทรก CSS ภายในหน้าเว็บ คุณยังระบุสตริงที่จะใช้ในพร็อพเพอร์ตี้ css ได้ด้วย ตัวเลือกนี้ใช้ได้กับ scripting.insertCSS() เท่านั้น คุณ
จะรันสตริงโดยใช้ scripting.executeScript() ไม่ได้
function getTabId() { ... }
const css = "body { background-color: red; }";
chrome.scripting
.insertCSS({
target : {tabId : getTabId()},
css : css,
})
.then(() => console.log("CSS injected"));
จัดการผลลัพธ์
ระบบจะส่งผลลัพธ์ของการเรียกใช้ JavaScript ไปยังส่วนขยาย รวมผลลัพธ์เดียว ต่อเฟรม รับประกันว่าเฟรมหลักจะเป็นดัชนีแรกในอาร์เรย์ที่ได้ ส่วนเฟรมอื่นๆ ทั้งหมดจะอยู่ในลำดับที่ไม่แน่นอน
function getTabId() { ... }
function getTitle() { return document.title; }
chrome.scripting
.executeScript({
target : {tabId : getTabId(), allFrames : true},
func : getTitle,
})
.then(injectionResults => {
for (const {frameId, result} of injectionResults) {
console.log(`Frame ${frameId} result:`, result);
}
});
scripting.insertCSS() ไม่แสดงผลลัพธ์ใดๆ
สัญญา
หากค่าที่ได้จากการเรียกใช้สคริปต์เป็น Promise Chrome จะรอให้ Promise เสร็จสมบูรณ์และแสดงผลค่าที่ได้
function getTabId() { ... }
async function addIframe() {
const iframe = document.createElement("iframe");
const loadComplete =
new Promise(resolve => iframe.addEventListener("load", resolve));
iframe.src = "https://example.com";
document.body.appendChild(iframe);
await loadComplete;
return iframe.contentWindow.document.title;
}
chrome.scripting
.executeScript({
target : {tabId : getTabId(), allFrames : true},
func : addIframe,
})
.then(injectionResults => {
for (const frameResult of injectionResults) {
const {frameId, result} = frameResult;
console.log(`Frame ${frameId} result:`, result);
}
});
ตัวอย่าง
ยกเลิกการลงทะเบียนสคริปต์เนื้อหาแบบไดนามิกทั้งหมด
ข้อมูลโค้ดต่อไปนี้มีฟังก์ชันที่ยกเลิกการลงทะเบียนสคริปต์เนื้อหาแบบไดนามิกทั้งหมด ที่ส่วนขยายได้ลงทะเบียนไว้ก่อนหน้านี้
async function unregisterAllDynamicContentScripts() {
try {
const scripts = await chrome.scripting.getRegisteredContentScripts();
const scriptIds = scripts.map(script => script.id);
return chrome.scripting.unregisterContentScripts({ ids: scriptIds });
} catch (error) {
const message = [
"An unexpected error occurred while",
"unregistering dynamic content scripts.",
].join(" ");
throw new Error(message, {cause : error});
}
}
หากต้องการลองใช้ chrome.scripting API
ให้ติดตั้งตัวอย่างการเขียนสคริปต์จากที่เก็บตัวอย่างส่วนขยาย Chrome
ประเภท
ContentScriptFilter
พร็อพเพอร์ตี้
-
ids
string[] ไม่บังคับ
หากระบุ
getRegisteredContentScriptsระบบจะแสดงเฉพาะสคริปต์ที่มีรหัสที่ระบุในรายการนี้เท่านั้น
CSSInjection
พร็อพเพอร์ตี้
-
CSS
สตริง ไม่บังคับ
สตริงที่มี CSS ที่จะแทรก ต้องระบุ
filesและcssอย่างใดอย่างหนึ่งเท่านั้น -
ไฟล์
string[] ไม่บังคับ
เส้นทางของไฟล์ CSS ที่จะแทรก ซึ่งสัมพันธ์กับไดเรกทอรีรากของส่วนขยาย ต้องระบุ
filesและcssอย่างใดอย่างหนึ่งเท่านั้น -
origin
StyleOrigin ไม่บังคับ
แหล่งที่มาของสไตล์สำหรับการแทรก ค่าเริ่มต้นคือ
'AUTHOR' -
เป้าหมาย
รายละเอียดที่ระบุเป้าหมายที่จะแทรก CSS
ExecutionWorld
โลกของ JavaScript สำหรับสคริปต์ที่จะดำเนินการภายใน
ค่าแจกแจง
"ISOLATED"
ระบุเวิลด์ที่แยกต่างหาก ซึ่งเป็นสภาพแวดล้อมการดำเนินการเฉพาะสำหรับส่วนขยายนี้
"MAIN"
ระบุโลกหลักของ DOM ซึ่งเป็นสภาพแวดล้อมการดำเนินการที่แชร์กับ JavaScript ของหน้าโฮสต์
InjectionResult
พร็อพเพอร์ตี้
-
documentId
สตริง
Chrome 106 ขึ้นไปเอกสารที่เชื่อมโยงกับการแทรก
-
frameId
ตัวเลข
Chrome 90 ขึ้นไปเฟรมที่เชื่อมโยงกับการแทรก
-
ผลลัพธ์
ไม่บังคับ
ผลลัพธ์ของการดำเนินการสคริปต์
InjectionTarget
พร็อพเพอร์ตี้
-
allFrames
บูลีน ไม่บังคับ
เลือกว่าสคริปต์ควรแทรกลงในเฟรมทั้งหมดภายในแท็บหรือไม่ ค่าเริ่มต้นคือ false ค่านี้ต้องเป็นเท็จหากมีการระบุ
frameIds -
documentIds
string[] ไม่บังคับ
Chrome 106 ขึ้นไปรหัสของ documentId ที่เฉพาะเจาะจงที่จะแทรก ห้ามตั้งค่านี้หากตั้งค่า
frameIdsไว้ -
frameIds
number[] ไม่บังคับ
รหัสของเฟรมที่เฉพาะเจาะจงที่จะแทรก
-
tabId
ตัวเลข
รหัสของแท็บที่จะแทรก
RegisteredContentScript
พร็อพเพอร์ตี้
-
allFrames
บูลีน ไม่บังคับ
หากระบุเป็นจริง ระบบจะแทรกลงในทุกเฟรม แม้ว่าเฟรมจะไม่ใช่เฟรมบนสุดในแท็บก็ตาม ระบบจะตรวจสอบแต่ละเฟรมแยกกันตามข้อกำหนดของ URL และจะไม่แทรกลงในเฟรมย่อยหากไม่เป็นไปตามข้อกำหนดของ URL ค่าเริ่มต้นคือ false ซึ่งหมายความว่าระบบจะจับคู่เฉพาะเฟรมบนสุด
-
CSS
string[] ไม่บังคับ
รายการไฟล์ CSS ที่จะแทรกลงในหน้าเว็บที่ตรงกัน ระบบจะแทรกข้อมูลเหล่านี้ตามลำดับที่ปรากฏในอาร์เรย์นี้ ก่อนที่จะสร้างหรือแสดง DOM ใดๆ สำหรับหน้าเว็บ
-
excludeMatches
string[] ไม่บังคับ
ยกเว้นหน้าเว็บที่สคริปต์เนื้อหานี้จะแทรกเข้าไป ดูรายละเอียดเพิ่มเติมเกี่ยวกับไวยากรณ์ของสตริงเหล่านี้ได้ที่รูปแบบการจับคู่
-
id
สตริง
รหัสของ Content Script ที่ระบุในการเรียก API ต้องไม่ขึ้นต้นด้วย "_" เนื่องจากสงวนไว้เป็นคำนำหน้าสำหรับรหัสสคริปต์ที่สร้างขึ้น
-
js
string[] ไม่บังคับ
รายการไฟล์ JavaScript ที่จะแทรกลงในหน้าเว็บที่ตรงกัน โดยจะแทรกตามลำดับที่ปรากฏในอาร์เรย์นี้
-
matchOriginAsFallback
บูลีน ไม่บังคับ
Chrome 119 ขึ้นไประบุว่าจะแทรกสคริปลงในเฟรมที่ URL มีรูปแบบที่ไม่รองรับได้หรือไม่ ซึ่งได้แก่ about:, data:, blob: หรือ filesystem: ในกรณีเหล่านี้ ระบบจะตรวจสอบต้นทางของ URL เพื่อพิจารณาว่าควรแทรกสคริปต์หรือไม่ หากต้นทางคือ
null(เช่นเดียวกับ URL ของข้อมูล) ต้นทางที่ใช้จะเป็นเฟรมที่สร้างเฟรมปัจจุบัน หรือเฟรมที่เริ่มการนำทางไปยังเฟรมนี้ โปรดทราบว่านี่อาจไม่ใช่เฟรมระดับบน -
ตรงกับ
string[] ไม่บังคับ
ระบุหน้าเว็บที่จะแทรกสคริปต์เนื้อหานี้ ดูรายละเอียดเพิ่มเติมเกี่ยวกับไวยากรณ์ของสตริงเหล่านี้ได้ที่รูปแบบการจับคู่ ต้องระบุสำหรับ
registerContentScripts -
persistAcrossSessions
บูลีน ไม่บังคับ
ระบุว่าสคริปต์เนื้อหานี้จะยังคงอยู่ในเซสชันในอนาคตหรือไม่ ค่าเริ่มต้นคือ True
-
runAt
RunAt ไม่บังคับ
ระบุเวลาที่แทรกไฟล์ JavaScript ลงในหน้าเว็บ ค่าที่ต้องการและค่าเริ่มต้นคือ
document_idle -
โลก
ExecutionWorld ไม่บังคับ
Chrome 102 ขึ้นไป"โลก" ของ JavaScript ที่ใช้เรียกใช้สคริปต์ ค่าเริ่มต้นคือ
ISOLATED
ScriptInjection
พร็อพเพอร์ตี้
-
args
any[] ไม่บังคับ
Chrome 92 ขึ้นไปอาร์กิวเมนต์ที่จะส่งไปยังฟังก์ชันที่ระบุ ซึ่งจะใช้ได้ก็ต่อเมื่อระบุพารามิเตอร์
funcอาร์กิวเมนต์เหล่านี้ต้องเป็น JSON ที่ทำให้เป็นอนุกรมได้ -
ไฟล์
string[] ไม่บังคับ
เส้นทางของไฟล์ JS หรือ CSS ที่จะแทรก ซึ่งสัมพันธ์กับไดเรกทอรีรูทของส่วนขยาย ต้องระบุ
filesหรือfuncอย่างใดอย่างหนึ่งเท่านั้น -
injectImmediately
บูลีน ไม่บังคับ
Chrome 102 ขึ้นไปควรทริกเกอร์การแทรกในเป้าหมายโดยเร็วที่สุดหรือไม่ โปรดทราบว่าการดำเนินการนี้ไม่ได้เป็นการรับประกันว่าจะมีการแทรกก่อนที่หน้าเว็บจะโหลด เนื่องจากหน้าเว็บอาจโหลดเสร็จแล้วเมื่อสคริปต์ไปถึงเป้าหมาย
-
เป้าหมาย
รายละเอียดที่ระบุเป้าหมายที่จะแทรกสคริปต์
-
โลก
ExecutionWorld ไม่บังคับ
Chrome 95 ขึ้นไป"โลก" ของ JavaScript ที่ใช้เรียกใช้สคริปต์ ค่าเริ่มต้นคือ
ISOLATED -
func
void optional
Chrome 92 ขึ้นไปฟังก์ชัน JavaScript ที่จะแทรก ระบบจะแปลงฟังก์ชันนี้เป็นอนุกรม แล้วจึงแปลงเป็นดีซีเรียลไลซ์เพื่อการแทรก ซึ่งหมายความว่าพารามิเตอร์ที่เชื่อมโยงและบริบทการดำเนินการจะหายไป ต้องระบุ
filesหรือfuncอย่างใดอย่างหนึ่งเท่านั้นฟังก์ชัน
funcมีลักษณะดังนี้() => {...}
StyleOrigin
แหล่งที่มาของการเปลี่ยนแปลงสไตล์ ดูข้อมูลเพิ่มเติมได้ที่แหล่งที่มาของสไตล์
ค่าแจกแจง
"AUTHOR"
"USER"
เมธอด
executeScript()
chrome.scripting.executeScript(
injection: ScriptInjection,
): Promise<InjectionResult[]>
แทรกสคริปต์ลงในบริบทเป้าหมาย โดยค่าเริ่มต้น สคริปต์จะทำงานที่ document_idle หรือทันทีหากหน้าเว็บโหลดแล้ว หากตั้งค่าพร็อพเพอร์ตี้ injectImmediately สคริปต์จะแทรกโดยไม่ต้องรอ แม้ว่าหน้าจะโหลดไม่เสร็จก็ตาม หากสคริปต์ประเมินเป็น Promise เบราว์เซอร์จะรอให้ Promise เสร็จสมบูรณ์และแสดงผลค่าที่ได้
พารามิเตอร์
-
การแทรก
รายละเอียดของสคริปต์ที่จะแทรก
การคืนสินค้า
-
Promise<InjectionResult[]>
Chrome 90 ขึ้นไปส่งคืน Promise ซึ่งจะได้รับการแก้ไขเมื่อการแทรกเสร็จสมบูรณ์ อาร์เรย์ที่ได้จะมีผลการดำเนินการสำหรับแต่ละเฟรมที่การแทรกสำเร็จ
getRegisteredContentScripts()
chrome.scripting.getRegisteredContentScripts(
filter?: ContentScriptFilter,
): Promise<RegisteredContentScript[]>
แสดงผลสคริปต์เนื้อหาที่ลงทะเบียนแบบไดนามิกทั้งหมดสำหรับส่วนขยายนี้ซึ่งตรงกับตัวกรองที่ระบุ
พารามิเตอร์
-
ตัวกรอง
ContentScriptFilter ไม่บังคับ
ออบเจ็กต์เพื่อกรองสคริปต์ที่ลงทะเบียนแบบไดนามิกของส่วนขยาย
การคืนสินค้า
-
Promise<RegisteredContentScript[]>
insertCSS()
chrome.scripting.insertCSS(
injection: CSSInjection,
): Promise<void>
แทรกสไตล์ชีต CSS ลงในบริบทเป้าหมาย หากระบุเฟรมหลายเฟรม ระบบจะละเว้นการแทรกที่ไม่สำเร็จ
พารามิเตอร์
-
การแทรก
รายละเอียดของสไตล์ที่จะแทรก
การคืนสินค้า
-
Promise<void>
Chrome 90 ขึ้นไปส่งคืน Promise ซึ่งจะได้รับการแก้ไขเมื่อการแทรกเสร็จสมบูรณ์
registerContentScripts()
chrome.scripting.registerContentScripts(
scripts: RegisteredContentScript[],
): Promise<void>
ลงทะเบียนสคริปต์เนื้อหาอย่างน้อย 1 รายการสำหรับส่วนขยายนี้
พารามิเตอร์
-
สคริปต์
มีรายการสคริปต์ที่จะลงทะเบียน หากมีข้อผิดพลาดระหว่างการแยกวิเคราะห์สคริปต์/การตรวจสอบไฟล์ หรือหากมีรหัสที่ระบุอยู่แล้ว ระบบจะไม่ลงทะเบียนสคริปต์
การคืนสินค้า
-
Promise<void>
แสดงผล Promise ซึ่งจะได้รับการแก้ไขเมื่อลงทะเบียนสคริปต์ทั้งหมดแล้ว หรือปฏิเสธหากเกิดข้อผิดพลาด
removeCSS()
chrome.scripting.removeCSS(
injection: CSSInjection,
): Promise<void>
นำสไตล์ชีต CSS ที่ส่วนขยายนี้แทรกไว้ก่อนหน้านี้ออกจากบริบทเป้าหมาย
พารามิเตอร์
-
การแทรก
รายละเอียดของสไตล์ที่จะนำออก โปรดทราบว่าพร็อพเพอร์ตี้
css,filesและoriginต้องตรงกับชีตสไตล์ที่แทรกผ่านinsertCSSทุกประการ การพยายามนำชีตสไตล์ที่ไม่มีอยู่ออกจะไม่มีผล
การคืนสินค้า
-
Promise<void>
แสดงผล Promise ซึ่งจะได้รับการแก้ไขเมื่อการนำออกเสร็จสมบูรณ์
unregisterContentScripts()
chrome.scripting.unregisterContentScripts(
filter?: ContentScriptFilter,
): Promise<void>
ยกเลิกการลงทะเบียนสคริปต์เนื้อหาสำหรับส่วนขยายนี้
พารามิเตอร์
-
ตัวกรอง
ContentScriptFilter ไม่บังคับ
หากระบุ ระบบจะยกเลิกการลงทะเบียนสคริปต์เนื้อหาแบบไดนามิกที่ตรงกับตัวกรองเท่านั้น มิเช่นนั้น ระบบจะยกเลิกการลงทะเบียนสคริปต์เนื้อหาแบบไดนามิกทั้งหมดของส่วนขยาย
การคืนสินค้า
-
Promise<void>
แสดงผล Promise ซึ่งจะได้รับการแก้ไขเมื่อยกเลิกการลงทะเบียนสคริปต์แล้ว หรือปฏิเสธหากเกิดข้อผิดพลาด
updateContentScripts()
chrome.scripting.updateContentScripts(
scripts: RegisteredContentScript[],
): Promise<void>
อัปเดต Content Script อย่างน้อย 1 รายการสำหรับส่วนขยายนี้
พารามิเตอร์
-
สคริปต์
มีรายการสคริปต์ที่จะอัปเดต ระบบจะอัปเดตพร็อพเพอร์ตี้สำหรับสคริปต์ที่มีอยู่ก็ต่อเมื่อมีการระบุในออบเจ็กต์นี้ หากมีข้อผิดพลาดระหว่างการแยกวิเคราะห์สคริปต์/การตรวจสอบไฟล์ หรือหากรหัสที่ระบุไม่ตรงกับสคริปต์ที่ลงทะเบียนอย่างสมบูรณ์ ระบบจะไม่ทำการอัปเดตสคริปต์
การคืนสินค้า
-
Promise<void>
แสดงผล Promise ซึ่งจะได้รับการแก้ไขเมื่ออัปเดตสคริปต์แล้ว หรือปฏิเสธหากเกิดข้อผิดพลาด