您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Greasy Fork is available in English.
SIMPLE TEXT NOTE FOR COPY 创建一个可编辑的浮窗记事本,默认包含10个记事栏目
当前为
// ==UserScript== // @name SIMPLE TEXT NOTE FOR COPY 浏览器浮窗记事本 // @namespace http://tampermonkey.net/ // @version 1.0 // @description SIMPLE TEXT NOTE FOR COPY 创建一个可编辑的浮窗记事本,默认包含10个记事栏目 // @author leifeng // @match *://*/* // @grant GM_addStyle // @license MIT // ==/UserScript== (function () { 'use strict'; // 样式定义 const style = ` .floating-notepad { position: fixed; bottom: -200px; /* 默认位置下移,只显示顶部 */ right: 20px; width: 300px; background-color: white; border-radius: 8px; box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15); z-index: 9999; transition: bottom 0.3s ease; font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen-Sans, Ubuntu, Cantarell, "Helvetica Neue", sans-serif; } .notepad-header { display: flex; justify-content: space-between; align-items: center; padding: 10px 15px; background-color: #4a6cf7; /* 默认蓝色 */ color: white; border-radius: 8px 8px 0 0; cursor: move; user-select: none; transition: background-color 0.3s ease; } .notepad-header.over-limit { background-color: #dc3545; /* 超过限制时显示红色 */ } .notepad-title { font-weight: 600; font-size: 15px; transition: all 0.3s ease; } .notepad-content { padding: 15px; max-height: 350px; display: flex; flex-direction: column; } .notepad-list { flex: 1; margin-bottom: 10px; max-height: 250px; overflow-y: auto; padding-right: 5px; } .notepad-item { padding: 8px 10px; margin-bottom: 8px; background-color: #f8f9fa; border-radius: 4px; font-size: 14px; line-height: 1.4; position: relative; transition: all 0.2s ease; min-height: 40px; } .notepad-item:hover { background-color: #f1f3f5; box-shadow: 0 2px 5px rgba(0, 0, 0, 0.05); } .notepad-item-empty { border: 1px dashed #ced4da; background-color: transparent; display: flex; align-items: center; color: #6c757d; font-size: 13px; } .notepad-item-empty:hover { border-color: #4a6cf7; color: #4a6cf7; } .notepad-item-text { padding: 0; } .notepad-item-char-count { font-size: 11px; color: #6c757d; margin-top: 3px; text-align: right; } .notepad-item-edit-area { width: 100%; padding: 5px; border: 1px solid #ced4da; border-radius: 4px; font-size: 14px; resize: none; margin-bottom: 3px; box-sizing: border-box; min-height: 40px; background-color: white; } .notepad-item-edit-area.expanded { position: fixed; top: 50%; left: 50%; transform: translate(-50%, -50%); width: calc(100% - 40px); max-width: 500px; height: calc(100% - 100px); max-height: 400px; z-index: 10000; font-size: 16px; box-shadow: 0 10px 25px rgba(0, 0, 0, 0.2); } .notepad-footer { display: flex; justify-content: space-between; align-items: center; margin-top: 5px; } .notepad-count { font-size: 12px; color: #6c757d; } .notepad-clear-all { font-size: 12px; color: #dc3545; cursor: pointer; text-decoration: underline; transition: color 0.2s ease; } .notepad-clear-all:hover { color: #c82333; } `; // 添加样式 GM_addStyle(style); // 存储键名 const STORAGE_KEY = 'floating_notepad_items'; const MAX_CHAR_COUNT = 500; // 最大字符数限制 const DEFAULT_TITLE = '浮窗记事本'; // 默认标题 // 创建记事本元素 function createNotepad() { // 主容器 const container = document.createElement('div'); container.className = 'floating-notepad'; // 头部 const header = document.createElement('div'); header.className = 'notepad-header'; const title = document.createElement('div'); title.className = 'notepad-title'; title.textContent = DEFAULT_TITLE; header.appendChild(title); // 内容区域 const content = document.createElement('div'); content.className = 'notepad-content'; // 列表区域 const listContainer = document.createElement('div'); listContainer.className = 'notepad-list'; // 底部区域 const footer = document.createElement('div'); footer.className = 'notepad-footer'; const countIndicator = document.createElement('div'); countIndicator.className = 'notepad-count'; updateCountIndicator(); const clearAllBtn = document.createElement('div'); clearAllBtn.className = 'notepad-clear-all'; clearAllBtn.textContent = '清除所有'; clearAllBtn.addEventListener('click', clearAllNotes); footer.appendChild(countIndicator); footer.appendChild(clearAllBtn); content.appendChild(listContainer); content.appendChild(footer); container.appendChild(header); container.appendChild(content); document.body.appendChild(container); // 状态管理 let isDragging = false; let offsetY = 0; let expandedItemId = null; let currentEditingId = null; // 当前正在编辑的项目 ID const DRAG_SPEED_FACTOR = 1.5; // 拖拽速度因子,增加后拖拽更快 // 加载已保存的笔记 loadNotes(); // 拖动功能 header.addEventListener('mousedown', startDrag); document.addEventListener('mousemove', handleDrag); document.addEventListener('mouseup', stopDrag); // 点击外部关闭展开的编辑框 document.addEventListener('click', (e) => { if (expandedItemId && !e.target.closest('.notepad-item-edit-area.expanded')) { collapseAllEditors(); } }); // ESC 键关闭展开的编辑框 document.addEventListener('keydown', (e) => { if (e.key === 'Escape' && expandedItemId) { collapseAllEditors(); } }); // 函数定义 function startDrag(e) { e.preventDefault(); isDragging = true; // 计算鼠标在头部的垂直偏移 const rect = header.getBoundingClientRect(); offsetY = e.clientY - rect.top; // 提升层级 container.style.zIndex = "10000"; // 添加样式 header.style.cursor = 'grabbing'; } function handleDrag(e) { if (!isDragging) return; // 计算新的 top 值,保持鼠标与顶部的距离一致 const newTop = e.clientY - offsetY; // 转换为 bottom 值,并应用速度因子 const newBottom = window.innerHeight - newTop - container.offsetHeight; // 限制移动范围,确保不会完全移出屏幕 const minBottom = -container.offsetHeight + header.offsetHeight; const maxBottom = window.innerHeight - header.offsetHeight; // 应用拖拽速度因子 container.style.bottom = Math.max(minBottom, Math.min(maxBottom, newBottom * DRAG_SPEED_FACTOR)) + "px"; } function stopDrag() { if (!isDragging) return; isDragging = false; container.style.zIndex = "9999"; header.style.cursor = 'move'; } function loadNotes() { let items = getSavedItems(); // 如果没有保存的笔记,创建 10 个空的笔记 if (items.length === 0) { items = Array.from({ length: 10 }, (_, i) => ({ id: Date.now() + i, text: '', timestamp: new Date().toISOString() })); saveItems(items); } renderNotes(items); } function renderNotes(items) { listContainer.innerHTML = ''; items.forEach(item => { const noteEl = document.createElement('div'); noteEl.className = item.text ? 'notepad-item' : 'notepad-item notepad-item-empty'; noteEl.dataset.id = item.id; // 创建查看模式元素 const viewMode = document.createElement('div'); viewMode.className = 'notepad-item-view-mode'; const textEl = document.createElement('div'); textEl.className = 'notepad-item-text'; textEl.textContent = item.text || '点击编辑...'; const charCountEl = document.createElement('div'); charCountEl.className = 'notepad-item-char-count'; charCountEl.textContent = item.text ? `${item.text.length}/${MAX_CHAR_COUNT}` : `0/${MAX_CHAR_COUNT}`; viewMode.appendChild(textEl); viewMode.appendChild(charCountEl); // 创建编辑模式元素 const editMode = document.createElement('div'); editMode.className = 'notepad-item-edit-mode'; editMode.style.display = 'none'; const editArea = document.createElement('textarea'); editArea.className = 'notepad-item-edit-area'; editArea.value = item.text; editArea.maxLength = MAX_CHAR_COUNT; // 设置最大长度 const editCharCountEl = document.createElement('div'); editCharCountEl.className = 'notepad-item-char-count'; editCharCountEl.textContent = `${item.text.length}/${MAX_CHAR_COUNT}`; editMode.appendChild(editArea); editMode.appendChild(editCharCountEl); // 添加到笔记元素 noteEl.appendChild(viewMode); noteEl.appendChild(editMode); // 点击进入编辑模式 noteEl.addEventListener('click', (e) => { currentEditingId = item.id; switchToEditMode(noteEl, item); // 延迟扩展,确保编辑模式已激活 setTimeout(() => { expandEditor(editArea, item.id); checkCharCount(editArea); // 初始检查 }, 10); }); // 编辑区域输入事件 editArea.addEventListener('input', () => { const length = editArea.value.length; editCharCountEl.textContent = `${length}/${MAX_CHAR_COUNT}`; checkCharCount(editArea); }); // 粘贴事件,处理超限情况 editArea.addEventListener('paste', () => { setTimeout(() => { const length = editArea.value.length; editCharCountEl.textContent = `${length}/${MAX_CHAR_COUNT}`; checkCharCount(editArea); }, 10); // 等待粘贴完成 }); // 失去焦点事件 editArea.addEventListener('blur', () => { saveEditedNote(item.id, editArea.value); collapseAllEditors(); resetHeader(); // 重置标题栏 currentEditingId = null; }); // 按 Enter 换行,Shift+Enter 保存 editArea.addEventListener('keydown', (e) => { if (e.key === 'Enter') { if (e.shiftKey) { // Shift+Enter:保存 e.preventDefault(); editArea.blur(); } else { // Enter:正常换行 // 默认行为,不需要阻止 } } }); listContainer.appendChild(noteEl); }); updateCountIndicator(items.length); } function switchToEditMode(noteEl, item) { // 关闭其他所有编辑模式 document.querySelectorAll('.notepad-item-edit-mode').forEach(el => { if (el.parentElement.dataset.id !== item.id) { el.style.display = 'none'; el.parentElement.querySelector('.notepad-item-view-mode').style.display = 'block'; if (!el.parentElement.querySelector('.notepad-item-text').textContent.trim()) { el.parentElement.classList.add('notepad-item-empty'); } } }); // 切换当前笔记到编辑模式 const viewMode = noteEl.querySelector('.notepad-item-view-mode'); const editMode = noteEl.querySelector('.notepad-item-edit-mode'); const editArea = editMode.querySelector('.notepad-item-edit-area'); noteEl.classList.remove('notepad-item-empty'); viewMode.style.display = 'none'; editMode.style.display = 'block'; editArea.focus(); } function expandEditor(editArea, itemId) { // 先折叠所有已展开的编辑器 collapseAllEditors(); // 展开当前编辑器 editArea.classList.add('expanded'); expandedItemId = itemId; // 存储光标位置 const cursorPos = editArea.selectionStart; // 重新设置光标位置 setTimeout(() => { editArea.focus(); editArea.setSelectionRange(cursorPos, cursorPos); }, 10); } function collapseAllEditors() { document.querySelectorAll('.notepad-item-edit-area.expanded').forEach(el => { el.classList.remove('expanded'); }); expandedItemId = null; } function saveEditedNote(id, newText) { // 限制文本长度不超过最大值 if (newText.length > MAX_CHAR_COUNT) { newText = newText.substring(0, MAX_CHAR_COUNT); } newText = newText.trim(); const items = getSavedItems(); const itemIndex = items.findIndex(item => item.id === id); if (itemIndex !== -1) { items[itemIndex].text = newText; items[itemIndex].timestamp = new Date().toISOString(); saveItems(items); renderNotes(items); } resetHeader(); // 保存后重置标题栏 } function checkCharCount(editArea) { const length = editArea.value.length; // 当字符数达到或超过限制时显示红色标题 if (length >= MAX_CHAR_COUNT) { title.textContent = '字符数达限制'; header.classList.add('over-limit'); } else { title.textContent = DEFAULT_TITLE; header.classList.remove('over-limit'); } } function resetHeader() { title.textContent = DEFAULT_TITLE; header.classList.remove('over-limit'); } function clearAllNotes() { if (confirm('确定要清除所有笔记吗?')) { // 创建 10 个空笔记而不是完全清空 const emptyItems = Array.from({ length: 10 }, (_, i) => ({ id: Date.now() + i, text: '', timestamp: new Date().toISOString() })); saveItems(emptyItems); renderNotes(emptyItems); } } function getSavedItems() { try { const saved = sessionStorage.getItem(STORAGE_KEY); return saved ? JSON.parse(saved) : []; } catch (e) { console.error('Failed to load notes:', e); return []; } } function saveItems(items) { try { sessionStorage.setItem(STORAGE_KEY, JSON.stringify(items)); } catch (e) { console.error('Failed to save notes:', e); } } function updateCountIndicator(count = 0) { countIndicator.textContent = `共 ${count} 条笔记`; } } // 初始化记事本 createNotepad(); })();