前言
在 FB 上看到臉友抱怨爲什麼留言系統預設是最相關,每次都要點擊切換,很麻煩。
安裝 tampermonkey
這軟體是拿來讓使用者可以自己寫腳本,可以讓網頁變成自定義。
Eddie 這次寫的腳本就是在 tampermonkey 的基礎上做出來的,請先下載。
打開開發人員模式
在「設定」-「擴孔功能」-「管理擴充功能」裡面,打開「開發人員模式」。
這是必要的,讓 tampermonkey 有權限操作你想要執行的腳本。
開啓 tampermonkey 界面
點擊 「tampermonkey 圖標」-「控制檯」,即可進入後臺界面。
接著點擊「+」製作新腳本。
複製以下:
// ==UserScript==
// @name Facebook - Default to All Comments
// @name:zh-TW Facebook - 預設顯示所有留言
// @namespace http://tampermonkey.net/
// @version 0.5
// @description Automatically changes the default comment sort on Facebook from "Most Relevant" to "All Comments".
// @description:zh-TW 自動將 Facebook 貼文留言排序從「最相關」切換為「所有留言」。
// @author Eddie Lu using Gemini 2.5 pro
// @match *://*.facebook.com/*
// @grant none
// @run-at document-idle
// @license MIT
// ==/UserScript==
(function() {
'use strict';
// --- 設定 ---
const CHECK_INTERVAL_MS = 1500; // 每隔多少毫秒檢查一次頁面 (例如 1.5 秒)
const CLICK_DELAY_MS = 300; // 點擊排序按鈕後,等待多少毫秒再點擊選項
// --- 需要尋找的文字 (需要與你的 Facebook 語言介面對應) ---
// 這些是常見的文字,如果你的介面不同,可能需要修改
const mostRelevantTexts = ["Most Relevant", "最相關"]; // 目前顯示為「最相關」時的文字
const allCommentsTexts = ["All Comments", "所有留言", "Newest", "最新"]; // 要點擊的選項文字 (包含 "Newest" 因為有時 FB 合併了)
// --- 尋找排序按鈕的策略 ---
// Facebook 結構常變,這裡結合多種方式提高成功率
// 1. 透過 aria-label (無障礙標籤)
// 2. 透過按鈕內的文字內容
// --- 尋找排序按鈕的策略 (更新) ---
// 優先尋找 role="button" 的 div,再檢查文字
// aria-label 作為備用策略
const sortButtonSelectors = [
'div[role="button"]', // *** 主要目標:尋找所有 role="button" 的 div ***
'span[role="button"]', // 也考慮 span 按鈕的可能性
// 保留 aria-label 作為其他 FB 版本的備用方案
'div[role="button"][aria-label*="Sort comments by"]',
'div[role="button"][aria-label*="留言排序依據"]',
'div[role="button"][aria-label*="Comment sort order"]',
];
// --- 輔助函數:模擬真實點擊 ---
function simulateClick(element) {
const mouseEventInit = { bubbles: true, cancelable: true, view: window };
const mouseDownEvent = new MouseEvent('mousedown', mouseEventInit);
const mouseUpEvent = new MouseEvent('mouseup', mouseEventInit);
const clickEvent = new MouseEvent('click', mouseEventInit);
element.dispatchEvent(mouseDownEvent);
element.dispatchEvent(mouseUpEvent);
element.dispatchEvent(clickEvent);
}
// --- 主要執行函數 ---
function findAndSwitchComments() {
// 尋找所有可能的排序觸發按鈕
let potentialTriggers = [];
sortButtonSelectors.forEach(selector => {
document.querySelectorAll(selector).forEach(el => {
// 如果是 span,嘗試找到它外層可點擊的 button
let clickableElement = el.closest('div[role="button"], span[role="button"]');
if (!clickableElement && el.tagName === 'SPAN') {
// 如果 span 本身不是按鈕,檢查它的內容是否符合
const currentText = el.textContent?.trim();
if (currentText && mostRelevantTexts.some(text => currentText.includes(text))) {
// 向上查找可點擊的父元素
clickableElement = el.closest('div[role="button"], span[role="button"], div[tabindex="0"]'); // 擴大範圍
}
} else if (el.tagName === 'DIV' && el.getAttribute('role') === 'button') {
// 如果本身就是 button div
clickableElement = el;
}
if (clickableElement && !potentialTriggers.includes(clickableElement)) {
potentialTriggers.push(clickableElement);
}
});
});
potentialTriggers.forEach(trigger => {
// 檢查按鈕目前的文字是否為 "最相關"
const currentButtonText = trigger.textContent?.trim();
const needsSwitch = currentButtonText && mostRelevantTexts.some(text => currentButtonText.includes(text));
// 加上一個標記避免重複處理同一個按鈕 (防止快速連點)
if (needsSwitch && !trigger.dataset.switchInProgress) {
console.log("發現 '最相關' 排序按鈕:", trigger, "準備切換...");
trigger.dataset.switchInProgress = 'true'; // 標記處理中
// 模擬點擊排序按鈕以打開選單
simulateClick(trigger);
// 等待選單彈出
setTimeout(() => {
// 尋找「所有留言」或「最新」選項
let allCommentsOption = null;
// 選單通常在 body 下,所以全局搜索
const menuItems = document.querySelectorAll('div[role="menuitemradio"], div[role="menuitem"], div[role="option"]'); // 包含可能的角色
menuItems.forEach(item => {
const itemText = item.textContent?.trim();
if (itemText && allCommentsTexts.some(text => itemText.includes(text))) { // <--- 修改這裡,從 === 改成 includes // 確保選項是可見的 (一個基本的檢查)
if (item.offsetParent !== null || item.closest('[role="dialog"], [role="menu"]')) {
allCommentsOption = item;
return; // 找到就停止
}
}
});
if (allCommentsOption) {
console.log("找到 '所有留言/最新' 選項:", allCommentsOption, "點擊中...");
// 模擬點擊「所有留言」選項
simulateClick(allCommentsOption);
console.log("已切換為 '所有留言/最新'.");
// 成功切換後,過一段時間再移除標記,允許它在需要時再次被檢查
setTimeout(() => {
delete trigger.dataset.switchInProgress;
}, 1000); // 等待 1 秒後移除標記
} else {
console.log("錯誤:點擊了排序按鈕,但找不到 '所有留言/最新' 選項。可能是 Facebook 介面變動。");
// 如果找不到選項,也要移除標記,允許下次重試
delete trigger.dataset.switchInProgress;
}
}, CLICK_DELAY_MS);
} else if (trigger.dataset.switchInProgress && !needsSwitch) {
// 如果標記還在,但文字已經不是 "最相關",表示可能已切換成功或被用戶手動切換
delete trigger.dataset.switchInProgress;
}
});
}
// --- 定期執行檢查 ---
console.log("Facebook [預設顯示所有留言] 腳本已啟動。");
// 使用 MutationObserver 監聽 DOM 變化,比 setInterval 更有效率
const observer = new MutationObserver((mutationsList, observer) => {
// 不用檢查具體的 mutation,只要有變化就嘗試執行一次
findAndSwitchComments();
});
// 設定觀察目標為整個 body,監聽子節點和子樹的變化
observer.observe(document.body, { childList: true, subtree: true });
// 也可以保留一個定時器作為備用,以防 MutationObserver 遺漏某些情況 (例如頁面滾動加載)
setInterval(findAndSwitchComments, CHECK_INTERVAL_MS * 2); // 定時器的頻率可以設低一些
// 頁面剛載入完成時也執行一次
setTimeout(findAndSwitchComments, 1000);
})();
點擊「檔案」-「儲存」後退出檔案。
啓用腳本
記得啓用腳本,再到 FB測試吧!
>> Home