คำอธิบาย
ใช้ userScripts API เพื่อเรียกใช้สคริปต์ของผู้ใช้ในบริบทสคริปต์ของผู้ใช้
สิทธิ์
userScriptsหากต้องการใช้ User Scripts API browser.userScripts ให้เพิ่มสิทธิ์ "userScripts" ลงใน manifest.json และ "host_permissions" สำหรับเว็บไซต์ที่ต้องการเรียกใช้สคริปต์
{
"name": "User script test extension",
"manifest_version": 3,
"minimum_chrome_version": "120",
"permissions": [
"userScripts"
],
"host_permissions": [
"*://example.com/*"
]
}
ความพร้อมใช้งาน
แนวคิดและการใช้งาน
สคริปต์ผู้ใช้คือข้อมูลโค้ดที่แทรกลงในหน้าเว็บเพื่อแก้ไขลักษณะที่ปรากฏหรือลักษณะการทำงานของหน้าเว็บ User Scripts API ช่วยให้คุณเรียกใช้โค้ดที่กำหนดเองได้ ซึ่งแตกต่างจากฟีเจอร์ส่วนขยายอื่นๆ เช่น สคริปต์เนื้อหาและ browser.scripting API API นี้จำเป็นสำหรับส่วนขยายที่เรียกใช้สคริปต์ที่ผู้ใช้ระบุซึ่งไม่สามารถจัดส่งเป็นส่วนหนึ่งของแพ็กเกจส่วนขยายได้
เปิดใช้การใช้ userScripts API
หลังจากส่วนขยายได้รับสิทธิ์ใช้ userScripts API แล้ว ผู้ใช้ต้องเปิดใช้ปุ่มเปิด/ปิดที่เฉพาะเจาะจงเพื่ออนุญาตให้ส่วนขยายใช้ API ได้ ปุ่มเปิด/ปิดที่เฉพาะเจาะจงที่จำเป็นและลักษณะการทำงานของ API เมื่อปิดใช้จะแตกต่างกันไปตามเวอร์ชัน Chrome
ใช้การตรวจสอบต่อไปนี้เพื่อระบุว่าผู้ใช้ต้องเปิดใช้ปุ่มสลับใด เช่น ในระหว่างการเริ่มต้นใช้งานของผู้ใช้ใหม่
let version = Number(navigator.userAgent.match(/(Chrome|Chromium)\/([0-9]+)/)?.[2]);
if (version >= 138) {
// Allow User Scripts toggle will be used.
} else {
// Developer mode toggle will be used.
}
ส่วนต่อไปนี้จะอธิบายปุ่มเปิด/ปิดต่างๆ และวิธีเปิดใช้
Chrome เวอร์ชันก่อน 138 (ปุ่มเปิด/ปิดโหมดนักพัฒนาซอฟต์แวร์)
ในฐานะนักพัฒนาส่วนขยาย คุณได้เปิดใช้โหมดนักพัฒนาซอฟต์แวร์ในการติดตั้ง Chrome แล้ว ผู้ใช้ของคุณต้องเปิดใช้โหมดนักพัฒนาซอฟต์แวร์ด้วย
คุณสามารถคัดลอกและวางวิธีการต่อไปนี้ลงในเอกสารประกอบของส่วนขยายสำหรับผู้ใช้
- ไปที่หน้าส่วนขยายโดยป้อน
chrome://extensionsในแท็บใหม่ (URL ของchrome://ไม่สามารถลิงก์ได้ตามการออกแบบ) เปิดใช้โหมดนักพัฒนาซอฟต์แวร์โดยคลิกสวิตช์เปิด/ปิดข้างโหมดนักพัฒนาซอฟต์แวร์
หน้าส่วนขยาย (chrome://extensions)
Chrome เวอร์ชัน 138 ขึ้นไป (ปุ่มเปิด/ปิด "อนุญาตสคริปต์ของผู้ใช้")
ปุ่มเปิด/ปิดอนุญาตสคริปต์ของผู้ใช้จะอยู่ในหน้ารายละเอียดของส่วนขยายแต่ละรายการ (เช่น chrome://extensions/?id=YOUR_EXTENSION_ID)
คุณสามารถคัดลอกและวางวิธีการต่อไปนี้ลงในเอกสารประกอบของส่วนขยายสำหรับผู้ใช้ได้
- ไปที่หน้าส่วนขยายโดยป้อน
chrome://extensionsในแท็บใหม่ (URL ของchrome://ไม่สามารถลิงก์ได้ตามการออกแบบ) - คลิกปุ่ม "รายละเอียด" บนการ์ดส่วนขยายเพื่อดูข้อมูลโดยละเอียดเกี่ยวกับส่วนขยาย
- คลิกปุ่มเปิด/ปิดข้างอนุญาตสคริปต์ของผู้ใช้
ตรวจสอบความพร้อมใช้งานของ API
เราขอแนะนำให้ตรวจสอบต่อไปนี้เพื่อดูว่า userScripts API เปิดใช้อยู่หรือไม่ เนื่องจาก API นี้ใช้ได้กับ Chrome ทุกเวอร์ชัน การตรวจสอบนี้พยายามเรียกใช้เมธอด browser.userScripts() ซึ่งควรจะสำเร็จเสมอเมื่อ API พร้อมใช้งาน หากการเรียกนี้แสดงข้อผิดพลาด แสดงว่า API ไม่พร้อมใช้งาน
function isUserScriptsAvailable() {
try {
// Method call which throws if API permission or toggle is not enabled.
browser.userScripts.getScripts();
return true;
} catch {
// Not available.
return false;
}
}
ทำงานในโลกที่แยกต่างหาก
ทั้งสคริปต์ของผู้ใช้และสคริปต์เนื้อหาจะทำงานในโลกที่แยกต่างหากหรือในโลกหลักก็ได้ Isolated World คือสภาพแวดล้อมการดำเนินการที่หน้าโฮสต์หรือส่วนขยายอื่นๆ เข้าถึงไม่ได้ ซึ่งช่วยให้สคริปต์ของผู้ใช้เปลี่ยนสภาพแวดล้อม JavaScript ได้โดยไม่ส่งผลกระทบต่อหน้าโฮสต์หรือสคริปต์ของผู้ใช้และเนื้อหาของส่วนขยายอื่นๆ ในทางกลับกัน สคริปต์ของผู้ใช้ (และสคริปต์เนื้อหา) จะไม่ปรากฏในหน้าโฮสต์หรือสคริปต์ของผู้ใช้และเนื้อหาของส่วนขยายอื่นๆ สคริปต์ที่ทำงานใน Main World จะเข้าถึงได้โดยหน้าโฮสต์และส่วนขยายอื่นๆ และจะมองเห็นได้โดยหน้าโฮสต์และส่วนขยายอื่นๆ หากต้องการเลือกโลก ให้ส่ง "USER_SCRIPT" หรือ "MAIN" เมื่อเรียกใช้ userScripts.register()
หากต้องการกำหนดค่านโยบายความปลอดภัยของเนื้อหาสำหรับโลก USER_SCRIPT ให้เรียกใช้ userScripts.configureWorld() ดังนี้
browser.userScripts.configureWorld({
csp: "script-src 'self'"
});
การรับส่งข้อความ
สคริปต์ของผู้ใช้จะสื่อสารกับส่วนอื่นๆ ของส่วนขยายโดยใช้การรับส่งข้อความ (ซึ่งหมายความว่าสคริปต์จะเรียกใช้ runtime.sendMessage() และ runtime.connect() ได้เหมือนกับส่วนอื่นๆ ของส่วนขยาย) เช่นเดียวกับสคริปต์เนื้อหาและเอกสารนอกหน้าจอ อย่างไรก็ตาม ระบบจะรับข้อความเหล่านี้โดยใช้ตัวแฮนเดิลเหตุการณ์เฉพาะ (ซึ่งหมายความว่าไม่ได้ใช้ onMessage หรือ onConnect) ตัวแฮนเดิลเหล่านี้เรียกว่า runtime.onUserScriptMessage และ runtime.onUserScriptConnect เครื่องมือจัดการเฉพาะช่วยให้ระบุข้อความจากสคริปต์ของผู้ใช้ได้ง่ายขึ้น ซึ่งเป็นบริบทที่เชื่อถือได้น้อยกว่า
ก่อนส่งข้อความ คุณต้องเรียกใช้ configureWorld() โดยตั้งค่าอาร์กิวเมนต์ messaging เป็น true โปรดทราบว่าคุณสามารถส่งทั้งอาร์กิวเมนต์ csp และ messaging พร้อมกันได้
browser.userScripts.configureWorld({
messaging: true
});
การอัปเดตส่วนขยาย
ระบบจะล้างสคริปต์ของผู้ใช้เมื่อส่วนขยายอัปเดต คุณเพิ่มกลับมาได้โดยเรียกใช้โค้ดในตัวแฮนเดิลเหตุการณ์ runtime.onInstalled ใน Service Worker ของส่วนขยาย ตอบสนองต่อเหตุผล "update" ที่ส่งไปยัง Callback ของเหตุการณ์เท่านั้น
ตัวอย่าง
ตัวอย่างนี้มาจากตัวอย่าง userScript ในที่เก็บตัวอย่างของเรา
ลงทะเบียนสคริปต์
ตัวอย่างต่อไปนี้แสดงการเรียกใช้ register() พื้นฐาน อาร์กิวเมนต์แรกคืออาร์เรย์ของออบเจ็กต์ที่กำหนดสคริปต์ที่จะลงทะเบียน ยังมีตัวเลือกอื่นๆ นอกเหนือจากที่แสดงที่นี่
browser.userScripts.register([{
id: 'test',
matches: ['*://*/*'],
js: [{code: 'alert("Hi!")'}]
}]);
ประเภท
ExecutionWorld
สภาพแวดล้อม JavaScript สำหรับสคริปต์ของผู้ใช้ที่จะเรียกใช้ภายใน
ค่าแจกแจง
"MAIN"
ระบุสภาพแวดล้อมการดำเนินการของ DOM ซึ่งเป็นสภาพแวดล้อมการดำเนินการที่ใช้ร่วมกับ JavaScript ของหน้าโฮสต์
"USER_SCRIPT"
ระบุสภาพแวดล้อมการดำเนินการที่เจาะจงสำหรับสคริปต์ของผู้ใช้และได้รับการยกเว้นจาก CSP ของหน้าเว็บ
InjectionResult
พร็อพเพอร์ตี้
-
documentId
สตริง
เอกสารที่เชื่อมโยงกับการฉีดวัคซีน
-
ข้อผิดพลาด
สตริง ไม่บังคับ
ข้อผิดพลาด (หากมี)
errorและresultจะเป็นข้อมูลแยกกัน -
frameId
ตัวเลข
เฟรมที่เชื่อมโยงกับการแทรก
-
ผลลัพธ์
ไม่บังคับ
ผลลัพธ์ของการเรียกใช้สคริปต์
InjectionTarget
พร็อพเพอร์ตี้
-
allFrames
บูลีน ไม่บังคับ
สคริปต์ควรแทรกลงในเฟรมทั้งหมดภายในแท็บหรือไม่ ค่าเริ่มต้นคือ "เท็จ" ค่านี้ต้องเป็นเท็จหากระบุ
frameIds -
documentIds
string[] ไม่บังคับ
รหัสของ documentId ที่เฉพาะเจาะจงที่จะแทรกเข้าไป ต้องไม่ตั้งค่านี้หากตั้งค่า
frameIdsไว้ -
frameIds
number[] ไม่บังคับ
รหัสของเฟรมที่เฉพาะเจาะจงที่จะแทรกเข้าไป
-
tabId
ตัวเลข
รหัสของแท็บที่จะแทรก
RegisteredUserScript
พร็อพเพอร์ตี้
-
allFrames
บูลีน ไม่บังคับ
หากเป็นจริง ระบบจะแทรกลงในเฟรมทั้งหมด แม้ว่าเฟรมนั้นจะไม่ใช่เฟรมบนสุดในแท็บก็ตาม ระบบจะตรวจสอบแต่ละเฟรมแยกกันตามข้อกำหนด URL และจะไม่แทรกลงในเฟรมย่อยหากไม่เป็นไปตามข้อกำหนด URL ค่าเริ่มต้นคือ "เท็จ" ซึ่งหมายความว่าจะจับคู่เฉพาะเฟรมบนสุดเท่านั้น
-
excludeGlobs
string[] ไม่บังคับ
ระบุรูปแบบไวลด์การ์ดสำหรับหน้าเว็บที่จะไม่แทรกสคริปต์ของผู้ใช้นี้
-
excludeMatches
string[] ไม่บังคับ
ยกเว้นหน้าเว็บที่สคริปต์ของผู้ใช้นี้จะแทรกเข้าไป ดูรายละเอียดเพิ่มเติมเกี่ยวกับไวยากรณ์ของสตริงเหล่านี้ได้ที่รูปแบบการจับคู่
-
id
สตริง
รหัสของสคริปต์ผู้ใช้ที่ระบุในการเรียก API พร็อพเพอร์ตี้นี้ต้องไม่ขึ้นต้นด้วย "_" เนื่องจากสงวนไว้เป็นคำนำหน้าสำหรับรหัสสคริปต์ที่สร้างขึ้น
-
includeGlobs
string[] ไม่บังคับ
ระบุรูปแบบไวลด์การ์ดสำหรับหน้าเว็บที่จะแทรกสคริปต์ของผู้ใช้นี้
-
js
ScriptSource[] ไม่บังคับ
รายการออบเจ็กต์ ScriptSource ที่กำหนดแหล่งที่มาของสคริปต์ที่จะแทรกลงในหน้าที่ตรงกัน คุณต้องระบุพร็อพเพอร์ตี้นี้สำหรับ ${ref:register} และเมื่อระบุแล้ว พร็อพเพอร์ตี้นี้ต้องเป็นอาร์เรย์ที่ไม่ว่างเปล่า
-
ตรงกับ
string[] ไม่บังคับ
ระบุหน้าเว็บที่จะแทรกสคริปต์ของผู้ใช้นี้ ดูรายละเอียดเพิ่มเติมเกี่ยวกับไวยากรณ์ของสตริงเหล่านี้ได้ที่รูปแบบการจับคู่ คุณต้องระบุพร็อพเพอร์ตี้นี้สำหรับ ${ref:register}
-
runAt
RunAt ไม่บังคับ
ระบุเวลาที่แทรกไฟล์ JavaScript ลงในหน้าเว็บ ค่าที่แนะนำและค่าเริ่มต้นคือ
document_idle -
โลก
ExecutionWorld ไม่บังคับ
สภาพแวดล้อมการดำเนินการ JavaScript ที่จะเรียกใช้สคริปต์ โดยมีค่าเริ่มต้นเป็น
`USER_SCRIPT` -
worldId
สตริง ไม่บังคับ
Chrome 133 ขึ้นไป browser.* ตั้งแต่ Chrome 148ระบุรหัสโลกของสคริปต์ผู้ใช้ที่จะเรียกใช้ หากละเว้น สคริปต์จะทำงานในสภาพแวดล้อมสคริปต์ของผู้ใช้เริ่มต้น ใช้ได้ก็ต่อเมื่อละเว้น
worldหรือเป็นUSER_SCRIPTระบบจะสงวนค่าที่มีขีดล่าง (_) นำหน้าไว้
ScriptSource
พร็อพเพอร์ตี้
-
รหัส
สตริง ไม่บังคับ
สตริงที่มีโค้ด JavaScript ที่จะแทรก ต้องระบุ
fileหรือcodeอย่างใดอย่างหนึ่ง -
ไฟล์
สตริง ไม่บังคับ
เส้นทางของไฟล์ JavaScript ที่จะแทรกโดยสัมพันธ์กับไดเรกทอรีรากของส่วนขยาย ต้องระบุ
fileหรือcodeอย่างใดอย่างหนึ่ง
UserScriptFilter
พร็อพเพอร์ตี้
-
ids
string[] ไม่บังคับ
getScriptsจะแสดงเฉพาะสคริปต์ที่มีรหัสที่ระบุไว้ในรายการนี้
UserScriptInjection
พร็อพเพอร์ตี้
-
injectImmediately
บูลีน ไม่บังคับ
ควรทริกเกอร์การแทรกในเป้าหมายโดยเร็วที่สุดหรือไม่ โปรดทราบว่าวิธีนี้ไม่ได้รับประกันว่าการแทรกจะเกิดขึ้นก่อนการโหลดหน้าเว็บ เนื่องจากหน้าเว็บอาจโหลดแล้วเมื่อสคริปต์ไปถึงเป้าหมาย
-
js
รายการออบเจ็กต์ ScriptSource ที่กำหนดแหล่งที่มาของสคริปต์ที่จะแทรกลงในเป้าหมาย
-
เป้าหมาย
รายละเอียดที่ระบุเป้าหมายที่จะแทรกสคริปต์
-
โลก
ExecutionWorld ไม่บังคับ
"โลก" ของ JavaScript ที่จะเรียกใช้สคริปต์ โดยมีค่าเริ่มต้นเป็น
USER_SCRIPT -
worldId
สตริง ไม่บังคับ
ระบุรหัสโลกของสคริปต์ผู้ใช้ที่จะเรียกใช้ หากละเว้น สคริปต์จะทำงานในสภาพแวดล้อมสคริปต์ของผู้ใช้เริ่มต้น ใช้ได้ก็ต่อเมื่อละเว้น
worldหรือเป็นUSER_SCRIPTระบบจะสงวนค่าที่มีขีดล่าง (_) นำหน้าไว้
WorldProperties
พร็อพเพอร์ตี้
-
csp
สตริง ไม่บังคับ
ระบุ CSP ทั่วโลก ค่าเริ่มต้นคือ CSP ทั่วโลกของ
`ISOLATED` -
ส่งข้อความ
บูลีน ไม่บังคับ
ระบุว่าจะแสดง API การรับส่งข้อความหรือไม่ โดยมีค่าเริ่มต้นเป็น
false -
worldId
สตริง ไม่บังคับ
Chrome 133 ขึ้นไป browser.* ตั้งแต่ Chrome 148ระบุรหัสของสคริปต์ผู้ใช้ที่เฉพาะเจาะจงที่จะอัปเดต หากไม่ได้ระบุ ระบบจะอัปเดตพร็อพเพอร์ตี้ของสคริปต์ผู้ใช้เริ่มต้น ระบบจะสงวนค่าที่มีขีดล่าง (
_) นำหน้าไว้
เมธอด
configureWorld()
browser.userScripts.configureWorld(
properties: WorldProperties,
): Promise<void>
กำหนดค่าสภาพแวดล้อมการดำเนินการ `USER_SCRIPT`
พารามิเตอร์
-
พร็อพเพอร์ตี้
มีการกำหนดค่าสภาพแวดล้อมของสคริปต์ผู้ใช้
การคืนสินค้า
-
Promise<void>
Promise ที่จะได้รับการแก้ไขเมื่อกำหนดค่าโลกแล้ว
execute()
browser.userScripts.execute(
injection: UserScriptInjection,
): Promise<InjectionResult[]>
แทรกสคริปต์ลงในบริบทเป้าหมาย โดยค่าเริ่มต้น สคริปต์จะทำงานที่ document_idle หรือทันทีหากหน้าเว็บโหลดแล้ว หากตั้งค่าพร็อพเพอร์ตี้ injectImmediately ไว้ สคริปต์จะแทรกโดยไม่ต้องรอ แม้ว่าหน้าเว็บจะยังโหลดไม่เสร็จก็ตาม หากสคริปต์ประเมินเป็น Promise เบราว์เซอร์จะรอให้ Promise ดำเนินการเสร็จสิ้นและแสดงผลลัพธ์
พารามิเตอร์
-
การฉีด
การคืนสินค้า
-
Promise<InjectionResult[]>
getScripts()
browser.userScripts.getScripts(
filter?: UserScriptFilter,
): Promise<RegisteredUserScript[]>
แสดงสคริปต์ของผู้ใช้ที่ลงทะเบียนแบบไดนามิกทั้งหมดสำหรับส่วนขยายนี้
พารามิเตอร์
-
ตัวกรอง
UserScriptFilter ไม่บังคับ
หากระบุไว้ เมธอดนี้จะแสดงเฉพาะสคริปต์ของผู้ใช้ที่ตรงกันเท่านั้น
การคืนสินค้า
-
Promise<RegisteredUserScript[]>
Promise ที่แก้ไขด้วยสคริปต์ที่ลงทะเบียน ระบบจะปฏิเสธ Promise หากเกิดข้อผิดพลาด
getWorldConfigurations()
browser.userScripts.getWorldConfigurations(): Promise<WorldProperties[]>
ดึงข้อมูลการกำหนดค่าโลกที่ลงทะเบียนไว้ทั้งหมด
การคืนสินค้า
-
Promise<WorldProperties[]>
Promise ที่แก้ไขด้วยการกำหนดค่าโลกที่ลงทะเบียนไว้
register()
browser.userScripts.register(
scripts: RegisteredUserScript[],
): Promise<void>
ลงทะเบียนสคริปต์ผู้ใช้อย่างน้อย 1 รายการสำหรับส่วนขยายนี้
พารามิเตอร์
-
สคริปต์
มีรายการสคริปต์ของผู้ใช้ที่จะลงทะเบียน
การคืนสินค้า
-
Promise<void>
Promise ที่จะได้รับการแก้ไขเมื่อลงทะเบียนสคริปต์อย่างสมบูรณ์แล้ว ระบบจะปฏิเสธ Promise หากเกิดข้อผิดพลาด
resetWorldConfiguration()
browser.userScripts.resetWorldConfiguration(
worldId?: string,
): Promise<void>
รีเซ็ตการกำหนดค่าสำหรับสภาพแวดล้อมสคริปต์ของผู้ใช้ สคริปต์ที่แทรกเข้าไปในโลกที่มีรหัสที่ระบุจะใช้การกำหนดค่าโลกเริ่มต้น
พารามิเตอร์
-
worldId
สตริง ไม่บังคับ
รหัสของ User Script World ที่จะรีเซ็ต หากละเว้น ระบบจะรีเซ็ตการกำหนดค่าของโลกเริ่มต้น
การคืนสินค้า
-
Promise<void>
Promise ที่จะได้รับการแก้ไขเมื่อรีเซ็ตการกำหนดค่า
unregister()
browser.userScripts.unregister(
filter?: UserScriptFilter,
): Promise<void>
ยกเลิกการลงทะเบียนสคริปต์ของผู้ใช้ที่ลงทะเบียนแบบไดนามิกทั้งหมดสำหรับส่วนขยายนี้
พารามิเตอร์
-
ตัวกรอง
UserScriptFilter ไม่บังคับ
หากระบุไว้ เมธอดนี้จะยกเลิกการลงทะเบียนเฉพาะสคริปต์ของผู้ใช้ที่ตรงกันเท่านั้น
การคืนสินค้า
-
Promise<void>
Promise ที่จะได้รับการแก้ไขเมื่อยกเลิกการลงทะเบียนสคริปต์อย่างสมบูรณ์แล้ว ระบบจะปฏิเสธ Promise หากเกิดข้อผิดพลาด
update()
browser.userScripts.update(
scripts: RegisteredUserScript[],
): Promise<void>
อัปเดตสคริปต์ของผู้ใช้อย่างน้อย 1 รายการสำหรับส่วนขยายนี้
พารามิเตอร์
-
สคริปต์
มีรายการสคริปต์ของผู้ใช้ที่จะอัปเดต ระบบจะอัปเดตพร็อพเพอร์ตี้สำหรับสคริปต์ที่มีอยู่ก็ต่อเมื่อมีการระบุไว้ในออบเจ็กต์นี้ หากมีข้อผิดพลาดระหว่างการแยกวิเคราะห์สคริปต์/การตรวจสอบไฟล์ หรือหากรหัสที่ระบุไม่สอดคล้องกับสคริปต์ที่ลงทะเบียนอย่างสมบูรณ์ ระบบจะไม่อัปเดตสคริปต์ใดๆ
การคืนสินค้า
-
Promise<void>
Promise ที่จะได้รับการแก้ไขเมื่อสคริปต์ได้รับการอัปเดตอย่างสมบูรณ์ ระบบจะปฏิเสธ Promise หากเกิดข้อผิดพลาด