diff --git a/package-lock.json b/package-lock.json
index 9fb9ec2..7a18029 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -12,6 +12,8 @@
"@testing-library/jest-dom": "^6.9.1",
"@testing-library/react": "^16.3.1",
"@testing-library/user-event": "^13.5.0",
+ "dexie": "^4.2.1",
+ "dexie-react-hooks": "^4.2.0",
"react": "^19.2.3",
"react-dom": "^19.2.3",
"react-markdown": "^10.1.0",
@@ -6703,6 +6705,23 @@
"url": "https://github.com/sponsors/wooorm"
}
},
+ "node_modules/dexie": {
+ "version": "4.2.1",
+ "resolved": "https://registry.npmmirror.com/dexie/-/dexie-4.2.1.tgz",
+ "integrity": "sha512-Ckej0NS6jxQ4Po3OrSQBFddayRhTCic2DoCAG5zacOfOVB9P2Q5Xc5uL/nVa7ZVs+HdMnvUPzLFCB/JwpB6Csg==",
+ "license": "Apache-2.0"
+ },
+ "node_modules/dexie-react-hooks": {
+ "version": "4.2.0",
+ "resolved": "https://registry.npmmirror.com/dexie-react-hooks/-/dexie-react-hooks-4.2.0.tgz",
+ "integrity": "sha512-u7KqTX9JpBQK8+tEyA9X0yMGXlSCsbm5AU64N6gjvGk/IutYDpLBInMYEAEC83s3qhIvryFS+W+sqLZUBEvePQ==",
+ "license": "Apache-2.0",
+ "peerDependencies": {
+ "@types/react": ">=16",
+ "dexie": ">=4.2.0-alpha.1 <5.0.0",
+ "react": ">=16"
+ }
+ },
"node_modules/didyoumean": {
"version": "1.2.2",
"resolved": "https://registry.npmmirror.com/didyoumean/-/didyoumean-1.2.2.tgz",
diff --git a/package.json b/package.json
index 80001b5..c2655d0 100644
--- a/package.json
+++ b/package.json
@@ -7,6 +7,8 @@
"@testing-library/jest-dom": "^6.9.1",
"@testing-library/react": "^16.3.1",
"@testing-library/user-event": "^13.5.0",
+ "dexie": "^4.2.1",
+ "dexie-react-hooks": "^4.2.0",
"react": "^19.2.3",
"react-dom": "^19.2.3",
"react-markdown": "^10.1.0",
diff --git a/src/App.js b/src/App.js
index 13403a8..acce7b5 100644
--- a/src/App.js
+++ b/src/App.js
@@ -4,13 +4,15 @@ import TimestampPage from './pages/TimestampPage';
import ElectronicWoodenFishPage from "./pages/ElectronicWoodenFishPage";
import TodoListPage from "./pages/TodoListPage";
import './App.css';
+import TestPage from "./pages/TestPage";
// 导航项配置数组,便于后续添加
// 为了测试折叠功能,我们添加更多导航项
const navItems = [
- {path: '/', label: 'Timestamp', element: },
+ {path: '/', label: '时间戳', element: },
{path: '/dzmy', label: '电子木鱼', element: },
{path: '/todo', label: '待办', element: },
+ {path: '/test', label: '测试', element: }
];
function App() {
diff --git a/src/pages/ElectronicWoodenFish.css b/src/pages/ElectronicWoodenFish.css
index b4a3ff6..1653dc5 100644
--- a/src/pages/ElectronicWoodenFish.css
+++ b/src/pages/ElectronicWoodenFish.css
@@ -30,6 +30,7 @@
border: 1px solid rgba(255, 255, 255, 0.05);
overflow: hidden;
padding: 20px;
+ margin-top: 20px;
}
/* 添加装饰性背景元素 */
diff --git a/src/pages/TestPage.js b/src/pages/TestPage.js
new file mode 100644
index 0000000..6e40272
--- /dev/null
+++ b/src/pages/TestPage.js
@@ -0,0 +1,111 @@
+import React, {useEffect} from 'react';
+import {db} from '../utils/db';
+import {useLiveQuery} from 'dexie-react-hooks';
+
+// 样式简单写一下,实际可以用 styled-components 或 css modules
+const styles = {
+ container: {padding: '20px', fontFamily: 'sans-serif', maxWidth: '600px', margin: '0 auto'},
+ uploadBox: {
+ border: '2px dashed #aaa',
+ padding: '40px',
+ textAlign: 'center',
+ background: '#f9f9f9',
+ marginBottom: '20px',
+ borderRadius: '8px'
+ },
+ grid: {display: 'grid', gridTemplateColumns: 'repeat(auto-fill, minmax(150px, 1fr))', gap: '10px'},
+ card: {border: '1px solid #eee', borderRadius: '8px', overflow: 'hidden', position: 'relative'},
+ img: {width: '100%', height: '120px', objectFit: 'cover', display: 'block'},
+ delBtn: {
+ position: 'absolute',
+ top: '5px',
+ right: '5px',
+ background: 'red',
+ color: 'white',
+ border: 'none',
+ cursor: 'pointer',
+ padding: '2px 8px',
+ borderRadius: '4px'
+ }
+};
+
+const TestPage = () => {
+ const images = useLiveQuery(() => db.images.orderBy('created').reverse().toArray());
+
+ // --- FIX 2: 修复重复粘贴问题 ---
+ useEffect(() => {
+ const handlePaste = async (event) => {
+ // 1. 获取剪贴板数据
+ const items = (event.clipboardData || event.originalEvent.clipboardData).items;
+
+ // 2. 找到第一个图片文件 (防止一次粘贴循环出多个格式)
+ let foundImage = false;
+
+ for (let item of items) {
+ if (!foundImage && item.kind === 'file' && item.type.includes('image/')) {
+ const blob = item.getAsFile();
+ foundImage = true; // 标记已找到,避免重复处理
+
+ // 3. 阻止默认行为(防止浏览器把图片直接贴到页面上)
+ event.preventDefault();
+
+ await db.images.add({
+ blob: blob,
+ created: new Date(),
+ source: 'Paste'
+ });
+
+ console.log('图片已添加');
+ }
+ }
+ };
+
+ // 添加监听
+ window.addEventListener('paste', handlePaste);
+
+ // ★★★ 关键:必须返回一个清理函数,组件刷新时移除旧的监听器 ★★★
+ return () => {
+ window.removeEventListener('paste', handlePaste);
+ };
+ }, []); // ★★★ 关键:依赖数组必须为空 [],保证只在挂载时绑定一次
+
+
+ // --- FIX 1: 修复删除变增加的问题 ---
+ const handleDelete = async (event, id) => {
+ // ★★★ 关键:阻止事件冒泡,防止触发父级的点击或粘贴逻辑
+ event.stopPropagation();
+
+ try {
+ await db.images.delete(id);
+ console.log('删除成功 ID:', id);
+ } catch (error) {
+ console.error('删除失败:', error);
+ }
+ };
+
+ return (
+
+
React 图片采集器 (已修复)
+
点击任意处粘贴 (Ctrl+V)
+
+
+ {images?.map((img) => (
+
+
+
+ {/* 传递 event 对象给 handleDelete */}
+
handleDelete(e, img.id)}
+ >
+ 删除
+
+
+
+ ))}
+
+
+ );
+}
+
+export default TestPage;
\ No newline at end of file
diff --git a/src/utils/db.js b/src/utils/db.js
new file mode 100644
index 0000000..32166ce
--- /dev/null
+++ b/src/utils/db.js
@@ -0,0 +1,7 @@
+import Dexie from "dexie";
+
+export const db = new Dexie("testImagesDb");
+
+db.version(1).stores({
+ images: '++id, created, source'
+});
\ No newline at end of file