您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Marketplace 排序上架日期控制面板
// ==UserScript== // @name FB Marketplace Item Sort // @namespace http://tampermonkey.net/ // @icon https://www.facebook.com/favicon.ico // @version 2025-09-24.2 // @description Marketplace 排序上架日期控制面板 // @author Henrik // @match *://www.facebook.com/* // @grant none // @run-at document-end // ==/UserScript== (function () { 'use strict'; const PANEL_ID = 'marketplace-control-panel'; const COLLAPSE_KEY = PANEL_ID + '-collapsed'; let panel = null; let container = null; // ---------- 建立控制面板 ---------- function createPanel() { if (panel) return; panel = document.createElement('div'); panel.id = PANEL_ID; panel.style.position = 'fixed'; panel.style.top = '80px'; panel.style.right = '20px'; // 固定在右側 panel.style.zIndex = '9999'; panel.style.width = '220px'; panel.style.background = 'rgba(255,255,255,0.97)'; panel.style.border = '1px solid #ddd'; panel.style.borderRadius = '8px'; panel.style.boxShadow = '0 4px 10px rgba(0,0,0,0.2)'; panel.style.fontFamily = 'system-ui, -apple-system, "Segoe UI", Roboto, Arial'; panel.style.fontSize = '14px'; panel.style.color = '#111'; // 標題列 const titleBar = document.createElement('div'); titleBar.style.display = 'flex'; titleBar.style.justifyContent = 'space-between'; titleBar.style.alignItems = 'center'; titleBar.style.padding = '4px 6px'; titleBar.style.background = '#f3f3f3'; titleBar.style.fontWeight = '600'; const title = document.createElement('div'); title.textContent = 'Marketplace 排序'; const toggleBtn = document.createElement('button'); toggleBtn.textContent = '-'; toggleBtn.style.border = 'none'; toggleBtn.style.cursor = 'pointer'; toggleBtn.style.fontSize = '16px'; toggleBtn.style.lineHeight = '1'; toggleBtn.style.padding = '0 6px'; titleBar.appendChild(title); titleBar.appendChild(toggleBtn); panel.appendChild(titleBar); // 控制項容器 container = document.createElement('div'); container.style.padding = '8px'; const controls = [ { label: '排序方式', param: 'sortBy', type: 'select', options: [ { text: '推薦', value: 'best_match' }, { text: '從近到遠', value: 'distance_ascend' }, { text: '由新到舊', value: 'creation_time_descend' }, { text: '價格低至高', value: 'price_ascend' }, { text: '價格高至低', value: 'price_descend' } ] }, { label: '上架日期(天)', param: 'daysSinceListed', type: 'select', options: [ { text: '不限', value: '' }, ...Array.from({ length: 30 }, (_, i) => ({ text: `${i + 1} 天內`, value: `${i + 1}` })) ] } ]; const inputs = {}; controls.forEach(ctrl => { const label = document.createElement('label'); label.textContent = ctrl.label; label.style.fontWeight = '500'; container.appendChild(label); if (ctrl.type === 'select') { const select = document.createElement('select'); select.style.width = '100%'; select.style.padding = '6px'; select.style.borderRadius = '6px'; select.style.border = '1px solid #ccc'; select.style.fontSize = '13px'; ctrl.options.forEach(opt => { const o = document.createElement('option'); o.value = opt.value; o.textContent = opt.text; select.appendChild(o); }); container.appendChild(select); inputs[ctrl.param] = select; } }); panel.appendChild(container); document.body.appendChild(panel); // 初始化 URL 參數 try { const url = new URL(window.location.href); controls.forEach(ctrl => { const val = url.searchParams.get(ctrl.param); if (val !== null && inputs[ctrl.param]) inputs[ctrl.param].value = val; }); } catch (e) { console.warn('URL 解析失敗', e); } // select 改變即更新 URL 並刷新頁面 function updateURL() { try { const newUrl = new URL(window.location.href); Object.entries(inputs).forEach(([param, el]) => { const value = el.value; if (value) newUrl.searchParams.set(param, value); else newUrl.searchParams.delete(param); }); window.location.href = newUrl.toString(); } catch (e) { console.error('更新 URL 失敗', e); } } Object.values(inputs).forEach(el => el.addEventListener('change', updateURL)); // ---------- 收合/展開 ---------- function setCollapsed(collapsed) { if (collapsed) { container.style.display = 'none'; panel.style.width = '160px'; toggleBtn.textContent = '+'; } else { container.style.display = 'block'; panel.style.width = '220px'; toggleBtn.textContent = '-'; } localStorage.setItem(COLLAPSE_KEY, collapsed ? '1' : '0'); } toggleBtn.addEventListener('click', () => { const isCollapsed = container.style.display !== 'none'; setCollapsed(isCollapsed); }); const savedCollapsed = localStorage.getItem(COLLAPSE_KEY); if (savedCollapsed === '1') setCollapsed(true); } function removePanel() { const p = document.getElementById(PANEL_ID); if (p) p.remove(); panel = null; } // ---------- 判斷是否顯示 ---------- function checkPanelVisibility() { const isMarketplacePage = !!window.location.pathname.match(/\/marketplace/); const isItemPage = window.location.pathname.includes('/item'); if (isItemPage || !isMarketplacePage) { if (panel) removePanel(); } else { if (!panel) createPanel(); } } // ---------- SPA 導航支援 ---------- (function () { const wrapHistory = function (type) { const orig = history[type]; return function () { const rv = orig.apply(this, arguments); setTimeout(checkPanelVisibility, 300); return rv; }; }; history.pushState = wrapHistory('pushState'); history.replaceState = wrapHistory('replaceState'); window.addEventListener('popstate', () => setTimeout(checkPanelVisibility, 300)); })(); // 初始檢查 checkPanelVisibility(); })();