图片粘贴上传实现

图片上传 html demo

直接粘贴本地运行查看效果即可,有看不懂的直接喂给 deepseek 会解释的很清晰

html 复制代码
<!DOCTYPE html>
<html lang="zh-CN">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>粘贴图片上传示例 - 使用场景,粘贴桌面图片上传、粘贴word 文档中图片上传、直接截图上传等</title>
  <style>
    body {
      font-family: Arial, sans-serif;
      padding: 20px;
    }
    .upload-area {
      width: 100%;
      height: 200px;
      border: 2px dashed #ccc;
      display: flex;
      align-items: center;
      justify-content: center;
      color: #666;
      font-size: 18px;
      margin-bottom: 20px;
    }
    .file-list {
      margin-top: 20px;
    }
    .file-item {
      margin-bottom: 10px;
      padding: 10px;
      border: 1px solid #ddd;
      background-color: #f9f9f9;
    }
    .file-item.uploading {
      background-color: #e0f7fa;
    }
    .file-item.done {
      background-color: #e8f5e9;
    }
    .file-item.error {
      background-color: #ffebee;
    }
  </style>
</head>
<body>
  <h1>粘贴图片上传示例</h1>
  <div class="upload-area">
    请在此区域粘贴图片
  </div>
  <div class="file-list">
    <h2>文件列表</h2>
    <div id="file-list-container"></div>
  </div>

  <script>
    // 模拟语言包
    const t = (key) => {
      const translations = {
        'examination.pasteNoContent': '粘贴内容为空',
      };
      return translations[key] || key;
    };

    // 生成唯一 ID
    const uuidv4 = () => {
      return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, (c) => {
        const r = (Math.random() * 16) | 0;
        const v = c === 'x' ? r : (r & 0x3) | 0x8;
        return v.toString(16);
      });
    };

    // 文件上传前的校验
    const onBeforeUpload = async (file, { maxHeight, maxWidth, size, maxCount, t, fileList }) => {
      if (fileList.length >= maxCount) {
        alert(`最多只能上传 ${maxCount} 张图片`);
        return false;
      }
      if (file.size > size) {
        alert(`文件大小不能超过 ${size / 1024 / 1024}MB`);
        return false;
      }
      return true;
    };

    // 模拟文件上传函数
    const fileUpload = (file, { onSuccess, onError }) => {
      setTimeout(() => {
        if (Math.random() > 0.5) {
          onSuccess({ url: 'https://example.com/uploaded-image.jpg' });
        } else {
          onError('上传失败,请重试');
        }
      }, 2000); // 模拟 2 秒上传时间
    };

    // 数据处理函数
    const dataHandle = ({ file, fileList }) => {
      return { file, fileList };
    };

    // 粘贴图片上传处理函数
    const handelPasteImageUpload = async (event, {
      t,
      resource = { images: [] },
      onStartUpload,
      onUploadSuccess,
      onUploadError,
      imageUploadLimitConfig,
    }) => {
      const fileList = resource.images || [];
      const clipboardData = event.clipboardData;
      if (clipboardData) {
        const items = clipboardData.items || [];
        if (items.length <= 0) {
          alert(t('examination.pasteNoContent'));
          return;
        }
        for (let i = 0; i < items.length; i++) {
          const item = items[i];
          if (item.type.indexOf('image') !== -1) {
            event.preventDefault(); // 阻止默认行为
            const originFileObj = item.getAsFile(); // 获取文件对象

            // 构建文件数据对象
            const fileDataObj = {
              originFileObj,
              uid: uuidv4(),
              lastModified: originFileObj.lastModified,
              name: originFileObj.name,
              size: originFileObj.size,
              type: originFileObj.type,
            };

            const { maxHeight, maxWidth, size, maxCount } = imageUploadLimitConfig;

            // 文件上传前的校验
            const flag = await onBeforeUpload(originFileObj, {
              maxHeight,
              maxWidth,
              size: size.image,
              maxCount: maxCount.image,
              t,
              fileList,
            });

            if (flag) {
              const newFileList = [...fileList, fileDataObj].map((item) => {
                if (item.uid === fileDataObj.uid) {
                  return { ...item, status: 'uploading' };
                }
                return item;
              });

              // 调用开始上传回调
              onStartUpload(dataHandle({ file: fileDataObj, fileList: newFileList }));

              // 模拟文件上传
              fileUpload(originFileObj, {
                onSuccess: (response) => {
                  const updatedFileList = newFileList.map((item) => {
                    if (item.uid === fileDataObj.uid) {
                      return { ...item, status: 'done', response };
                    }
                    return item;
                  });
                  onUploadSuccess(dataHandle({ file: fileDataObj, fileList: updatedFileList }));
                },
                onError: (error) => {
                  const updatedFileList = newFileList.map((item) => {
                    if (item.uid === fileDataObj.uid) {
                      return { ...item, status: 'error', response: error };
                    }
                    return item;
                  });
                  onUploadError(dataHandle({ file: fileDataObj, fileList: updatedFileList }));
                },
              });
            }
          }
        }
      }
    };

    // 初始化
    document.addEventListener('paste', (event) => {
      handelPasteImageUpload(event, {
        t,
        resource: { images: [] },
        onStartUpload: (data) => {
          console.log('开始上传:', data);
          renderFileList(data.fileList);
        },
        onUploadSuccess: (data) => {
          console.log('上传成功:', data);
          renderFileList(data.fileList);
        },
        onUploadError: (data) => {
          console.error('上传失败:', data);
          renderFileList(data.fileList);
        },
        imageUploadLimitConfig: {
          maxHeight: 1000,
          maxWidth: 1000,
          size: { image: 5 * 1024 * 1024 }, // 5MB
          maxCount: { image: 10 },
        },
      });
    });

    // 渲染文件列表
    const renderFileList = (fileList) => {
      const container = document.getElementById('file-list-container');
      container.innerHTML = fileList
        .map(
          (file) => `
          <div class="file-item ${file.status}">
            <strong>${file.name}</strong> - ${file.status}
            ${file.response ? `<br>响应: ${JSON.stringify(file.response)}` : ''}
          </div>
        `
        )
        .join('');
    };
  </script>
</body>
</html>
相关推荐
我命由我123452 小时前
React Router 6 - 编程式路由导航、useInRouterContext、useNavigationType
前端·javascript·react.js·前端框架·html·ecmascript·js
橙露3 小时前
JavaScript 异步编程:Promise、async/await 从原理到实战
开发语言·javascript·ecmascript
我命由我123454 小时前
React Router 6 - 嵌套路由、路由传递参数
前端·javascript·react.js·前端框架·html·ecmascript·js
十六年开源服务商4 小时前
2026年WordPress网站地图完整指南
java·前端·javascript
英俊潇洒美少年5 小时前
MessageChannel 如何实现时间切片
javascript·react.js·ecmascript
技术钱6 小时前
react数据大屏四种适配方案
javascript·react.js·ecmascript
李明卫杭州6 小时前
JavaScript 严格模式下 arguments 的区别
前端·javascript
一次旅行7 小时前
今日心理学知识分享(三)
开发语言·javascript·程序人生·ecmascript
牛十二7 小时前
openclaw安装mcporter搜索小红书
开发语言·javascript·ecmascript
小金鱼Y7 小时前
🔥 前端人必看:浏览器安全核心知识点全解析(XSS/CSRF/DDoS)
前端·javascript·安全