专栏文章
云剪贴板取缔计划
算法·理论参与者 1已保存评论 0
文章操作
快速查看文章及其快照的属性,并进行相关操作。
- 当前评论
- 0 条
- 当前快照
- 1 份
- 快照标识符
- @minls2jv
- 此快照首次捕获于
- 2025/12/02 04:29 3 个月前
- 此快照最后确认于
- 2025/12/02 04:29 3 个月前
洛谷的云剪贴板实在好用,我很多时候登洛谷就是为了用云剪贴板。所以,我决定自己写一个
CPP<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>快捷工具</title>
<!-- 引入Tailwind CSS -->
<script src="https://cdn.tailwindcss.com"></script>
<!-- 引入Font Awesome图标 -->
<link href="https://cdn.jsdelivr.net/npm/font-awesome@4.7.0/css/font-awesome.min.css" rel="stylesheet">
<!-- 配置Tailwind -->
<script>
tailwind.config = {
theme: {
extend: {
colors: {
primary: '#165DFF',
secondary: '#36CFC9',
dark: '#1D2129',
light: '#F2F3F5'
},
fontFamily: {
inter: ['Inter', 'system-ui', 'sans-serif'],
},
},
}
}
</script>
<style type="text/tailwindcss">
@layer utilities {
.content-auto {
content-visibility: auto;
}
.card-hover {
@apply transition-all duration-300 hover:shadow-lg hover:-translate-y-1;
}
.btn-effect {
@apply transform transition-all duration-200 active:scale-95;
}
}
</style>
</head>
<body class="font-inter bg-gray-50 min-h-screen">
<!-- 顶部导航 -->
<header class="bg-white shadow-sm sticky top-0 z-10">
<div class="container mx-auto px-4 py-4 flex justify-between items-center">
<h1 class="text-[clamp(1.5rem,3vw,2rem)] font-bold text-primary flex items-center">
<i class="fa fa-wrench mr-2"></i>快捷工具
</h1>
<div class="flex space-x-2">
<button id="clearAll" class="bg-red-500 text-white px-4 py-2 rounded-lg btn-effect flex items-center">
<i class="fa fa-trash mr-1"></i>清空
</button>
</div>
</div>
</header>
<main class="container mx-auto px-4 py-6">
<!-- 标签页切换 -->
<div class="flex border-b mb-6">
<button id="tabSites" class="px-6 py-3 font-medium text-primary border-b-2 border-primary">
<i class="fa fa-link mr-1"></i>网站快捷方式
</button>
<button id="tabNotes" class="px-6 py-3 font-medium text-gray-500 hover:text-primary transition-colors">
<i class="fa fa-sticky-note mr-1"></i>文本存储
</button>
</div>
<!-- 网站快捷方式区域 -->
<section id="sitesSection" class="space-y-6">
<!-- 添加网站表单 -->
<div class="bg-white p-4 rounded-xl shadow-sm">
<h2 class="text-lg font-semibold mb-4">添加新网站</h2>
<form id="addSiteForm" class="grid grid-cols-1 md:grid-cols-3 gap-4">
<div>
<label for="siteName" class="block text-sm font-medium text-gray-700 mb-1">网站名称</label>
<input type="text" id="siteName" placeholder="例如:洛谷"
class="w-full px-3 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-primary focus:border-primary transition-all">
</div>
<div>
<label for="siteUrl" class="block text-sm font-medium text-gray-700 mb-1">网站URL</label>
<input type="url" id="siteUrl" placeholder="例如:https://luogu.com"
class="w-full px-3 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-primary focus:border-primary transition-all">
</div>
<div class="flex items-end">
<button type="submit" class="w-full bg-primary text-white px-4 py-2 rounded-lg btn-effect flex items-center justify-center">
<i class="fa fa-plus mr-1"></i>添加
</button>
</div>
</form>
</div>
<!-- 网站列表 -->
<div>
<h2 class="text-lg font-semibold mb-4">已添加网站</h2>
<div id="sitesList" class="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-4">
<!-- 网站卡片将通过JS动态生成 -->
</div>
</div>
</section>
<!-- 文本存储区域 -->
<section id="notesSection" class="space-y-6 hidden">
<!-- 添加笔记表单 -->
<div class="bg-white p-4 rounded-xl shadow-sm">
<h2 class="text-lg font-semibold mb-4">添加新笔记</h2>
<form id="addNoteForm" class="space-y-4">
<div>
<label for="noteTitle" class="block text-sm font-medium text-gray-700 mb-1">笔记标题</label>
<input type="text" id="noteTitle" placeholder="例如:常用代码片段"
class="w-full px-3 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-primary focus:border-primary transition-all">
</div>
<div>
<label for="noteContent" class="block text-sm font-medium text-gray-700 mb-1">笔记内容</label>
<textarea id="noteContent" rows="4" placeholder="输入要保存的文字或代码..."
class="w-full px-3 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-primary focus:border-primary transition-all font-mono text-sm"></textarea>
</div>
<div class="flex justify-end">
<button type="submit" class="bg-primary text-white px-6 py-2 rounded-lg btn-effect flex items-center">
<i class="fa fa-save mr-1"></i>保存
</button>
</div>
</form>
</div>
<!-- 笔记列表 -->
<div>
<h2 class="text-lg font-semibold mb-4">已保存笔记</h2>
<div id="notesList" class="space-y-4">
<!-- 笔记卡片将通过JS动态生成 -->
</div>
</div>
</section>
</main>
<!-- 通知提示 -->
<div id="notification" class="fixed bottom-4 right-4 px-6 py-3 rounded-lg shadow-lg transform translate-y-20 opacity-0 transition-all duration-300 flex items-center">
<i id="notificationIcon" class="mr-2"></i>
<span id="notificationText"></span>
</div>
<script>
// 数据存储键名
const SITES_KEY = 'quickSites';
const NOTES_KEY = 'quickNotes';
// DOM元素
const tabSites = document.getElementById('tabSites');
const tabNotes = document.getElementById('tabNotes');
const sitesSection = document.getElementById('sitesSection');
const notesSection = document.getElementById('notesSection');
const addSiteForm = document.getElementById('addSiteForm');
const addNoteForm = document.getElementById('addNoteForm');
const sitesList = document.getElementById('sitesList');
const notesList = document.getElementById('notesList');
const clearAllBtn = document.getElementById('clearAll');
const notification = document.getElementById('notification');
const notificationIcon = document.getElementById('notificationIcon');
const notificationText = document.getElementById('notificationText');
// 初始化
document.addEventListener('DOMContentLoaded', () => {
loadSites();
loadNotes();
setupEventListeners();
});
// 设置事件监听器
function setupEventListeners() {
// 标签页切换
tabSites.addEventListener('click', () => {
switchToSitesTab();
});
tabNotes.addEventListener('click', () => {
switchToNotesTab();
});
// 添加网站表单提交
addSiteForm.addEventListener('submit', (e) => {
e.preventDefault();
addNewSite();
});
// 添加笔记表单提交
addNoteForm.addEventListener('submit', (e) => {
e.preventDefault();
addNewNote();
});
// 清空所有数据
clearAllBtn.addEventListener('click', () => {
if (confirm('确定要清空所有数据吗?此操作不可恢复!')) {
localStorage.removeItem(SITES_KEY);
localStorage.removeItem(NOTES_KEY);
sitesList.innerHTML = '';
notesList.innerHTML = '';
showNotification('所有数据已清空', 'fa-check-circle', 'bg-green-500');
}
});
}
// 切换到网站标签页
function switchToSitesTab() {
tabSites.classList.add('text-primary', 'border-b-2', 'border-primary');
tabSites.classList.remove('text-gray-500');
tabNotes.classList.remove('text-primary', 'border-b-2', 'border-primary');
tabNotes.classList.add('text-gray-500');
sitesSection.classList.remove('hidden');
notesSection.classList.add('hidden');
}
// 切换到笔记标签页
function switchToNotesTab() {
tabNotes.classList.add('text-primary', 'border-b-2', 'border-primary');
tabNotes.classList.remove('text-gray-500');
tabSites.classList.remove('text-primary', 'border-b-2', 'border-primary');
tabSites.classList.add('text-gray-500');
notesSection.classList.remove('hidden');
sitesSection.classList.add('hidden');
}
// 加载网站列表
function loadSites() {
const sites = JSON.parse(localStorage.getItem(SITES_KEY) || '[]');
sitesList.innerHTML = '';
if (sites.length === 0) {
sitesList.innerHTML = `
<div class="col-span-full text-center py-10 text-gray-500">
<i class="fa fa-link text-4xl mb-2 opacity-30"></i>
<p>还没有添加网站,点击上方表单添加</p>
</div>
`;
return;
}
sites.forEach((site, index) => {
const siteCard = document.createElement('div');
siteCard.className = 'bg-white rounded-xl shadow-sm p-4 card-hover';
siteCard.innerHTML = `
<div class="flex justify-between items-start mb-3">
<h3 class="font-semibold text-lg">${site.name}</h3>
<div class="flex space-x-1">
<button class="delete-site text-gray-400 hover:text-red-500 p-1" data-index="${index}">
<i class="fa fa-trash"></i>
</button>
</div>
</div>
<p class="text-sm text-gray-500 mb-3 truncate">${site.url}</p>
<a href="${site.url}" target="_blank" class="block w-full text-center bg-primary/10 text-primary px-4 py-2 rounded-lg hover:bg-primary/20 transition-colors btn-effect">
访问网站
</a>
`;
sitesList.appendChild(siteCard);
});
// 添加删除事件
document.querySelectorAll('.delete-site').forEach(btn => {
btn.addEventListener('click', (e) => {
const index = parseInt(e.currentTarget.dataset.index);
deleteSite(index);
});
});
}
// 添加新网站
function addNewSite() {
const nameInput = document.getElementById('siteName');
const urlInput = document.getElementById('siteUrl');
const name = nameInput.value.trim();
let url = urlInput.value.trim();
if (!name || !url) {
showNotification('请填写网站名称和URL', 'fa-exclamation-circle', 'bg-yellow-500');
return;
}
// 确保URL以http://或https://开头
if (!url.startsWith('http://') && !url.startsWith('https://')) {
url = 'https://' + url;
}
const sites = JSON.parse(localStorage.getItem(SITES_KEY) || '[]');
sites.push({ name, url });
localStorage.setItem(SITES_KEY, JSON.stringify(sites));
// 清空输入框
nameInput.value = '';
urlInput.value = '';
// 重新加载列表
loadSites();
showNotification('网站添加成功', 'fa-check-circle', 'bg-green-500');
}
// 删除网站
function deleteSite(index) {
const sites = JSON.parse(localStorage.getItem(SITES_KEY) || '[]');
sites.splice(index, 1);
localStorage.setItem(SITES_KEY, JSON.stringify(sites));
loadSites();
showNotification('网站已删除', 'fa-info-circle', 'bg-blue-500');
}
// 加载笔记列表
function loadNotes() {
const notes = JSON.parse(localStorage.getItem(NOTES_KEY) || '[]');
notesList.innerHTML = '';
if (notes.length === 0) {
notesList.innerHTML = `
<div class="text-center py-10 text-gray-500 bg-white rounded-xl p-4">
<i class="fa fa-sticky-note text-4xl mb-2 opacity-30"></i>
<p>还没有添加笔记,点击上方表单添加</p>
</div>
`;
return;
}
notes.forEach((note, index) => {
const noteCard = document.createElement('div');
noteCard.className = 'bg-white rounded-xl shadow-sm p-4 card-hover';
noteCard.innerHTML = `
<div class="flex justify-between items-start mb-3">
<h3 class="font-semibold text-lg">${note.title}</h3>
<div class="flex space-x-1">
<button class="copy-note text-gray-400 hover:text-green-500 p-1" data-index="${index}">
<i class="fa fa-copy"></i>
</button>
<button class="delete-note text-gray-400 hover:text-red-500 p-1" data-index="${index}">
<i class="fa fa-trash"></i>
</button>
</div>
</div>
<div class="bg-gray-50 p-3 rounded-lg text-sm font-mono overflow-x-auto max-h-40 mb-3">
<pre>${escapeHtml(note.content)}</pre>
</div>
<button class="w-full text-center bg-primary/10 text-primary px-4 py-2 rounded-lg hover:bg-primary/20 transition-colors copy-note btn-effect" data-index="${index}">
<i class="fa fa-copy mr-1"></i>复制内容
</button>
`;
notesList.appendChild(noteCard);
});
// 添加复制和删除事件
document.querySelectorAll('.copy-note').forEach(btn => {
btn.addEventListener('click', (e) => {
const index = parseInt(e.currentTarget.dataset.index);
copyNote(index);
});
});
document.querySelectorAll('.delete-note').forEach(btn => {
btn.addEventListener('click', (e) => {
const index = parseInt(e.currentTarget.dataset.index);
deleteNote(index);
});
});
}
// 添加新笔记
function addNewNote() {
const titleInput = document.getElementById('noteTitle');
const contentInput = document.getElementById('noteContent');
const title = titleInput.value.trim();
const content = contentInput.value.trim();
if (!title || !content) {
showNotification('请填写笔记标题和内容', 'fa-exclamation-circle', 'bg-yellow-500');
return;
}
const notes = JSON.parse(localStorage.getItem(NOTES_KEY) || '[]');
notes.push({ title, content });
localStorage.setItem(NOTES_KEY, JSON.stringify(notes));
// 清空输入框
titleInput.value = '';
contentInput.value = '';
// 重新加载列表
loadNotes();
showNotification('笔记保存成功', 'fa-check-circle', 'bg-green-500');
}
// 复制笔记内容
function copyNote(index) {
const notes = JSON.parse(localStorage.getItem(NOTES_KEY) || '[]');
const content = notes[index].content;
navigator.clipboard.writeText(content).then(() => {
showNotification('内容已复制到剪贴板', 'fa-check-circle', 'bg-green-500');
}).catch(err => {
showNotification('复制失败,请手动复制', 'fa-exclamation-circle', 'bg-red-500');
console.error('复制失败:', err);
});
}
// 删除笔记
function deleteNote(index) {
const notes = JSON.parse(localStorage.getItem(NOTES_KEY) || '[]');
notes.splice(index, 1);
localStorage.setItem(NOTES_KEY, JSON.stringify(notes));
loadNotes();
showNotification('笔记已删除', 'fa-info-circle', 'bg-blue-500');
}
// 显示通知
function showNotification(text, icon, bgColor) {
notificationText.textContent = text;
notificationIcon.className = `fa ${icon}`;
notification.className = `fixed bottom-4 right-4 px-6 py-3 rounded-lg shadow-lg transform translate-y-0 opacity-100 transition-all duration-300 flex items-center ${bgColor} text-white`;
setTimeout(() => {
notification.className = `fixed bottom-4 right-4 px-6 py-3 rounded-lg shadow-lg transform translate-y-20 opacity-0 transition-all duration-300 flex items-center ${bgColor} text-white`;
}, 3000);
}
// HTML转义,防止XSS
function escapeHtml(unsafe) {
return unsafe
.replace(/&/g, "&")
.replace(/</g, "<")
.replace(/>/g, ">")
.replace(/"/g, """)
.replace(/'/g, "'");
}
</script>
</body>
</html>
现在这个版本还有不少问题,这是我做的初稿,我会尝试改进
相关推荐
评论
共 0 条评论,欢迎与作者交流。
正在加载评论...