Greasy Fork is available in English.
收藏当前页、导出全部站点配置、位置记忆、可删除
// ==UserScript==
// @name 全局快捷平台跳转·收藏+导出+位置记忆
// @namespace http://tampermonkey.net/
// @version 2.3
// @description 收藏当前页、导出全部站点配置、位置记忆、可删除
// @match *://*/*
// @grant none
// @run-at document-idle
// ==/UserScript==
(function() {
'use strict';
const SITE_KEY = "quick_nav_all_sites";
const POS_KEY = "quick_nav_panel_position";
// 初始默认站点
const DEFAULT_SITES = [
{ name: "B站", url: "https://www.bilibili.com/" },
{ name: "X/Twitter", url: "https://x.com/" },
{ name: "YouTube", url: "https://www.youtube.com/" },
{ name: "Pinterest", url: "https://www.pinterest.com/" },
{ name: "TikTok", url: "https://www.tiktok.com/" },
{ name: "Kimi", url: "https://kimi.moonshot.cn/" },
{ name: "豆包", url: "https://www.doubao.com/" },
{ name: "百度", url: "https://www.baidu.com/" },
{ name: "Github", url: "https://github.com/" },
{ name: "知乎", url: "https://www.zhihu.com/" }
];
if (document.getElementById('quick-nav-panel')) return;
// 数据读写
function getSiteList() {
try {
const data = localStorage.getItem(SITE_KEY);
return data ? JSON.parse(data) : DEFAULT_SITES;
} catch {
return DEFAULT_SITES;
}
}
function saveSiteList(arr) {
localStorage.setItem(SITE_KEY, JSON.stringify(arr));
}
// 位置读写
function getPos() {
try {
return JSON.parse(localStorage.getItem(POS_KEY)) || { left: 20, top: 320 };
} catch {
return { left: 20, top: 320 };
}
}
function savePos(left, top) {
localStorage.setItem(POS_KEY, JSON.stringify({ left, top }));
}
// 容器初始化
const root = document.createElement('div');
root.id = 'quick-nav-panel';
const initPos = getPos();
root.style.cssText = `
all: initial;
position: fixed;
z-index: 9999998;
left: ${initPos.left}px;
top: ${initPos.top}px;
width: 180px;
font-family: system-ui, sans-serif;
user-select: none;
`;
document.body.appendChild(root);
// 顶部标题栏
const bar = document.createElement('div');
bar.style.cssText = `
background: #ff4081;
color: #fff;
padding: 10px 12px;
border-radius: 10px 10px 0 0;
font-size: 14px;
font-weight: 500;
display: flex;
justify-content: space-between;
align-items: center;
cursor: move;
`;
bar.innerHTML = `<span>快捷跳转</span><span id="nav-fold">−</span>`;
root.appendChild(bar);
// 内容面板
const panel = document.createElement('div');
panel.style.cssText = `
background: #fff;
border-radius: 0 0 10px 10px;
padding: 10px;
box-shadow: 0 4px 16px rgba(0,0,0,0.15);
max-height: 320px;
overflow-y: auto;
::-webkit-scrollbar { width: 5px; }
::-webkit-scrollbar-thumb { background: #ddd; border-radius: 5px; }
::-webkit-scrollbar-track { background: #f7f7f7; }
`;
root.appendChild(panel);
// 渲染列表
function renderList() {
panel.innerHTML = "";
const list = getSiteList();
list.forEach((item, idx) => {
const wrap = document.createElement('div');
wrap.style.display = "flex";
wrap.style.gap = "4px";
wrap.style.marginBottom = "6px";
const btn = document.createElement('div');
btn.style.cssText = `
flex:1; padding:8px 10px;
background:#f5f5f5; border-radius:6px;
font-size:13px; text-align:center; cursor:pointer;
`;
btn.textContent = item.name;
btn.onmouseover = () => btn.style.background = "#eaeaea";
btn.onmouseout = () => btn.style.background = "#f5f5f5";
btn.onclick = () => window.open(item.url, "_blank");
const del = document.createElement('span');
del.textContent = "×";
del.style.cssText = "color:#999; font-size:12px; cursor:pointer;";
del.onclick = (e) => {
e.stopPropagation();
list.splice(idx, 1);
saveSiteList(list);
renderList();
};
wrap.append(btn, del);
panel.appendChild(wrap);
});
// 功能按钮区
const toolBox = document.createElement('div');
toolBox.style.cssText = "margin-top:10px; display:flex; flex-direction:column; gap:6px;";
// 1.收藏当前页面
const collectBtn = document.createElement('button');
collectBtn.textContent = "收藏当前页面";
collectBtn.style.cssText = `
padding:7px; border:none; border-radius:6px;
background:#22c55e; color:#fff; font-size:12px; cursor:pointer;
`;
collectBtn.onclick = () => {
const name = document.title.substring(0, 20);
const url = location.href;
const arr = getSiteList();
arr.push({ name, url });
saveSiteList(arr);
renderList();
tip("已收藏当前页面");
};
// 2.导出全部站点(格式化JS数组,自动复制)
const exportBtn = document.createElement('button');
exportBtn.textContent = "导出全部站点";
exportBtn.style.cssText = `
padding:7px; border:none; border-radius:6px;
background:#1677ff; color:#fff; font-size:12px; cursor:pointer;
`;
exportBtn.onclick = () => {
const arr = getSiteList();
// 格式化为你脚本直接能用的 JS 数组格式
const code = `const SITES = ` + JSON.stringify(arr, null, 4) + `;`;
// 复制到剪贴板
navigator.clipboard.writeText(code).then(() => {
tip("已复制全部站点配置");
});
};
toolBox.appendChild(collectBtn);
toolBox.appendChild(exportBtn);
panel.appendChild(toolBox);
}
// 轻提示
function tip(text) {
const t = document.createElement('div');
t.textContent = text;
t.style.cssText = `
position:fixed; bottom:60px; left:50%;
transform:translateX(-50%); background:rgba(0,0,0,0.7);
color:#fff; padding:5px 12px; border-radius:4px;
font-size:12px; z-index:999999;
`;
document.body.appendChild(t);
setTimeout(() => t.remove(), 1500);
}
// 折叠
const foldBtn = document.getElementById('nav-fold');
foldBtn.style.cursor = "pointer";
foldBtn.onclick = () => {
const hide = panel.style.display === "none";
panel.style.display = hide ? "block" : "none";
foldBtn.textContent = hide ? "−" : "+";
bar.style.borderRadius = hide ? "10px" : "10px 10px 0 0";
};
// 拖拽+保存位置
let isDrag = false, startX, startY, lx, ly;
bar.addEventListener('mousedown', e => {
if (e.target === foldBtn) return;
isDrag = false;
startX = e.clientX;
startY = e.clientY;
lx = root.offsetLeft;
ly = root.offsetTop;
function move(e) {
const dx = e.clientX - startX;
const dy = e.clientY - startY;
if (Math.abs(dx) > 4 || Math.abs(dy) > 4) isDrag = true;
root.style.left = lx + dx + "px";
root.style.top = ly + dy + "px";
}
function up() {
document.removeEventListener('mousemove', move);
document.removeEventListener('mouseup', up);
if (isDrag) savePos(root.offsetLeft, root.offsetTop);
}
document.addEventListener('mousemove', move);
document.addEventListener('mouseup', up);
});
// 初始化
renderList();
// 默认永久折叠
panel.style.display = "none";
foldBtn.textContent = "+";
bar.style.borderRadius = "10px";
})();