1 Star 2 Fork 0

linfers/LinuxDo 浏览记录

加入 Gitee
与超过 1400万 开发者一起发现、参与优秀开源项目,私有仓库也完全免费 :)
免费加入
文件
克隆/下载
script_code 12.38 KB
一键复制 编辑 原始数据 按行查看 历史
linfers 提交于 2024-11-28 16:57 +08:00 . 增加移动按钮功能
// ==UserScript==
// @name Linux.do 帖子浏览记录
// @namespace http://tampermonkey.net/
// @version 1.5
// @description 记录最近浏览的10-20个帖子并提供快速访问,支持单条删除记录
// @author LiNFERS
// @match https://linux.do/*
// @grant GM_setValue
// @grant GM_getValue
// ==/UserScript==
(function () {
'use strict';
// 工具函数:设置样式
function setElementStyle(element, styles) {
for (const [key, value] of Object.entries(styles)) {
element.style[key] = value;
}
}
// 创建主按钮
const btn = document.createElement('button');
btn.innerHTML = '最近浏览';
setElementStyle(btn, {
position: 'fixed',
bottom: GM_getValue('btnBottom', '20px'),
right: GM_getValue('btnRight', '20px'),
zIndex: '9999',
padding: '10px 20px',
background: 'rgba(255, 255, 255, 0.6)',
color: '#333',
border: 'none',
borderRadius: '25px',
cursor: 'pointer',
backdropFilter: 'blur(5px)',
boxShadow: '0 2px 10px rgba(0,0,0,0.1)',
transition: 'all 0.3s ease',
});
document.body.appendChild(btn);
// 创建移动按钮
const moveBtn = document.createElement('button');
moveBtn.innerHTML = '↑↓';
setElementStyle(moveBtn, {
position: 'fixed',
bottom: GM_getValue('btnBottom', '20px'),
right: `${parseInt(GM_getValue('btnRight', '20px')) + btn.offsetWidth + 10}px`,
zIndex: '9999',
width: '30px',
height: '30px',
background: 'rgba(255, 255, 255, 0.6)',
color: '#333',
border: 'none',
borderRadius: '50%',
cursor: 'pointer',
backdropFilter: 'blur(5px)',
boxShadow: '0 2px 10px rgba(0,0,0,0.1)',
transition: 'all 0.3s ease',
fontSize: '16px',
display: 'flex',
alignItems: 'center',
justifyContent: 'center'
});
document.body.appendChild(moveBtn);
// 创建弹窗
const popup = document.createElement('div');
setElementStyle(popup, {
display: 'none',
position: 'fixed',
bottom: '80px',
right: '20px',
width: '300px',
maxHeight: '400px',
background: 'rgba(255, 255, 255, 0.95)',
borderRadius: '15px',
boxShadow: '0 2px 10px rgba(0,0,0,0.1)',
zIndex: '9999',
overflowY: 'auto',
padding: '10px',
backdropFilter: 'blur(10px)',
});
document.body.appendChild(popup);
// 移动功能
let isDragging = false;
let isMovable = false;
let startX, startY, initialX, initialY;
moveBtn.addEventListener('click', () => {
isMovable = !isMovable;
moveBtn.style.background = isMovable ? 'rgba(255, 68, 68, 0.9)' : 'rgba(255, 255, 255, 0.6)';
btn.style.cursor = isMovable ? 'move' : 'pointer';
});
btn.addEventListener('mousedown', startDragging);
btn.addEventListener('touchstart', startDragging, { passive: false });
function startDragging(e) {
if (!isMovable) return;
isDragging = true;
if (e.type === 'mousedown') {
startX = e.clientX;
startY = e.clientY;
} else {
e.preventDefault();
startX = e.touches[0].clientX;
startY = e.touches[0].clientY;
}
initialX = btn.offsetLeft;
initialY = btn.offsetTop;
document.addEventListener('mousemove', drag);
document.addEventListener('touchmove', drag, { passive: false });
document.addEventListener('mouseup', stopDragging);
document.addEventListener('touchend', stopDragging);
}
function drag(e) {
if (!isDragging) return;
e.preventDefault();
let currentX, currentY;
if (e.type === 'mousemove') {
currentX = e.clientX;
currentY = e.clientY;
} else {
currentX = e.touches[0].clientX;
currentY = e.touches[0].clientY;
}
const deltaX = currentX - startX;
const deltaY = currentY - startY;
const newLeft = initialX + deltaX;
const newTop = initialY + deltaY;
// 确保按钮不会超出视窗范围
const maxX = window.innerWidth - btn.offsetWidth;
const maxY = window.innerHeight - btn.offsetHeight;
const btnLeft = Math.min(Math.max(0, newLeft), maxX);
const btnTop = Math.min(Math.max(0, newTop), maxY);
// 更新按钮位置
const rightPos = `${window.innerWidth - btnLeft - btn.offsetWidth}px`;
const bottomPos = `${window.innerHeight - btnTop - btn.offsetHeight}px`;
btn.style.right = rightPos;
btn.style.bottom = bottomPos;
// 同步更新移动按钮位置
moveBtn.style.right = `${parseInt(rightPos) + btn.offsetWidth + 10}px`;
moveBtn.style.bottom = bottomPos;
// 保存位置
GM_setValue('btnRight', rightPos);
GM_setValue('btnBottom', bottomPos);
}
function stopDragging() {
if (isDragging) {
isDragging = false;
document.removeEventListener('mousemove', drag);
document.removeEventListener('touchmove', drag);
document.removeEventListener('mouseup', stopDragging);
document.removeEventListener('touchend', stopDragging);
}
}
let lastRecordedId = ''; // 记录最后一次记录的帖子 ID
function recordVisit() {
setTimeout(() => {
const path = window.location.pathname;
const postId = path.match(/\/t\/(\d+)/)?.[1] || path.match(/\/topic\/(\d+)/)?.[1];
if (!postId) return;
const title = document.querySelector('h1')?.textContent || document.title;
const url = window.location.href;
if (postId === lastRecordedId) return; // 避免重复记录
lastRecordedId = postId;
let history = GM_getValue('postHistory', []);
// 检查是否存在相同帖子 ID
const existingIndex = history.findIndex(item => item.id === postId);
if (existingIndex !== -1) {
history.splice(existingIndex, 1); // 删除重复记录
}
history.unshift({
id: postId,
title: title,
url: url,
time: new Date().toISOString(),
});
const maxRecords = Math.min(GM_getValue('maxRecords', 10), 20);
if (history.length > maxRecords) {
history = history.slice(0, maxRecords);
}
GM_setValue('postHistory', history);
}, 1000);
}
function showHistory() {
const history = GM_getValue('postHistory', []);
popup.innerHTML = '';
// 设置区域
const settingsDiv = document.createElement('div');
setElementStyle(settingsDiv, {
marginBottom: '10px',
padding: '5px',
borderBottom: '1px solid #eee',
display: 'flex',
justifyContent: 'space-between',
alignItems: 'center',
});
const settingsLabel = document.createElement('label');
settingsLabel.textContent = '记录条数: ';
const settingsInput = document.createElement('input');
settingsInput.type = 'number';
settingsInput.min = 1;
settingsInput.max = 20;
settingsInput.value = GM_getValue('maxRecords', 10);
setElementStyle(settingsInput, {
width: '60px',
margin: '0 5px',
padding: '3px',
borderRadius: '4px',
border: '1px solid #ddd',
});
settingsInput.onchange = (e) => {
let value = parseInt(e.target.value, 10);
value = Math.min(20, Math.max(1, value));
e.target.value = value;
GM_setValue('maxRecords', value);
};
const clearBtn = document.createElement('button');
clearBtn.textContent = '清空记录';
setElementStyle(clearBtn, {
padding: '5px 10px',
background: 'rgba(255, 68, 68, 0.9)',
color: 'white',
border: 'none',
borderRadius: '15px',
cursor: 'pointer',
transition: 'all 0.3s ease',
});
clearBtn.onclick = () => {
if (confirm('确定要清空所有浏览记录吗?')) {
GM_setValue('postHistory', []);
showHistory();
}
};
settingsDiv.appendChild(settingsLabel);
settingsDiv.appendChild(settingsInput);
settingsDiv.appendChild(clearBtn);
popup.appendChild(settingsDiv);
if (history.length === 0) {
popup.innerHTML += '<p style="text-align:center;color:#666;">暂无浏览记录</p>';
return;
}
// 展示记录
const ul = document.createElement('ul');
setElementStyle(ul, {
listStyle: 'none',
margin: '0',
padding: '0',
});
history.forEach((item, index) => {
const li = document.createElement('li');
setElementStyle(li, {
padding: '10px',
borderBottom: '1px solid #eee',
cursor: 'pointer',
transition: 'all 0.3s ease',
borderRadius: '8px',
display: 'flex',
justifyContent: 'space-between',
alignItems: 'center',
});
const time = new Date(item.time).toLocaleString();
const titleDiv = document.createElement('div');
titleDiv.innerHTML = `
<div style="font-size:14px;margin-bottom:5px;">${item.title}</div>
<div style="font-size:12px;color:#666;">${time}</div>
`;
titleDiv.style.flex = '1';
titleDiv.onclick = () => {
window.location.href = item.url;
};
const deleteBtn = document.createElement('button');
deleteBtn.textContent = '删除';
setElementStyle(deleteBtn, {
padding: '5px 10px',
background: 'rgba(255, 68, 68, 0.9)',
color: 'white',
border: 'none',
borderRadius: '8px',
cursor: 'pointer',
marginLeft: '10px',
});
deleteBtn.onclick = (e) => {
e.stopPropagation(); // 防止触发跳转
if (confirm(`确定删除记录 "${item.title}" 吗?`)) {
history.splice(index, 1);
GM_setValue('postHistory', history);
showHistory();
}
};
li.appendChild(titleDiv);
li.appendChild(deleteBtn);
ul.appendChild(li);
});
popup.appendChild(ul);
}
// 弹窗显示控制
let isPopupVisible = false;
btn.onclick = (e) => {
if (!isMovable) {
isPopupVisible = !isPopupVisible;
popup.style.display = isPopupVisible ? 'block' : 'none';
if (isPopupVisible) {
// 更新弹窗位置为按钮上方
const btnRect = btn.getBoundingClientRect();
const popupRight = window.innerWidth - btnRect.right;
popup.style.right = `${popupRight}px`;
popup.style.bottom = `${parseInt(btn.style.bottom) + btn.offsetHeight + 10}px`;
showHistory();
}
}
};
// 点击外部关闭弹窗
document.addEventListener('click', (e) => {
if (!popup.contains(e.target) && e.target !== btn && e.target !== moveBtn) {
popup.style.display = 'none';
isPopupVisible = false;
}
});
// 初始记录
recordVisit();
// 监听 URL 变化
let lastUrl = location.href;
new MutationObserver(() => {
if (location.href !== lastUrl) {
lastUrl = location.href;
recordVisit();
}
}).observe(document.body, { childList: true, subtree: true });
})();
Loading...
马建仓 AI 助手
尝试更多
代码解读
代码找茬
代码优化
JavaScript
1
https://gitee.com/linfers/linux-do-browsing-history.git
git@gitee.com:linfers/linux-do-browsing-history.git
linfers
linux-do-browsing-history
LinuxDo 浏览记录
master

搜索帮助