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