You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

在Next.js+Dropzone上传流程中用纯JS生成BlurHash

问题解答:上传图片时用纯JavaScript生成BlurHash

当然可以!你可以用官方的blurhash纯JS库(完全前端实现,无需第三方API)在上传环节生成BlurHash,之后和图片一起传到服务器,这样后续从服务器拉取动态图片时,就能直接把这个Hash传给Next.js的图片组件当占位符用。

实现步骤

1. 安装blurhash库

先在项目里装官方的blurhash包:

npm install blurhash
# 或用yarn
yarn add blurhash

2. 修改Dropzone的图片处理逻辑

在你的Dropzone代码里加入生成BlurHash的逻辑——核心是把图片画到Canvas上,提取像素数据后生成Hash。优化后的完整代码如下:

import { encode } from 'blurhash';
import { useDispatch, useSelector } from 'react-redux';
import { selectImages } from '你的redux路径'; // 替换成实际路径
import useDropzone from 'react-dropzone';
import imageCompression from 'browser-image-compression';
import { useState } from 'react';

const YourUploadComponent = () => {
  const dispatch = useDispatch();
  const images = useSelector(selectImages);
  const [files, setFiles] = useState(images.length === 0 ? [] : images);

  // 辅助函数:从图片URL生成BlurHash
  const generateBlurHash = async (imageUrl) => {
    return new Promise((resolve, reject) => {
      const img = new Image();
      img.crossOrigin = 'anonymous';
      img.onload = () => {
        const canvas = document.createElement('canvas');
        const ctx = canvas.getContext('2d');
        // 缩小图片尺寸提升生成效率(BlurHash不需要高分辨率)
        const width = Math.min(img.width, 64);
        const height = Math.min(img.height, 64);
        canvas.width = width;
        canvas.height = height;
        ctx.drawImage(img, 0, 0, width, height);
        
        const imageData = ctx.getImageData(0, 0, width, height);
        // 4,4是组件数,数值越小Hash越短、模糊感越强,反之则越接近原图
        const hash = encode(imageData.data, width, height, 4, 4);
        resolve(hash);
      };
      img.onerror = reject;
      img.src = imageUrl;
    });
  };

  const { getRootProps, getInputProps } = useDropzone({
    onDrop: async (acceptedFiles) => {
      // 先做数量校验
      const total = acceptedFiles.length + files.length;
      if (total > 9) {
        alert("最多选择9张图片");
        return;
      }
      if (acceptedFiles.length > 9) {
        alert("单次最多选择9张图片");
        return;
      }

      // 逐个处理文件
      for (const [index, file] of acceptedFiles.entries()) {
        // 检查文件名重复(若要更精准可对比文件哈希)
        const isDuplicate = files.some(existing => existing.name === file.name);
        if (isDuplicate) {
          alert(`检测到重复图片:${file.name}`);
          continue;
        }

        // 压缩图片
        const options = {
          maxSizeMB: 5,
          maxWidthOrHeight: 1920,
          useWebWorker: true,
        };
        const compressedFile = await imageCompression(file, options);
        
        // 生成预览URL
        const previewUrl = URL.createObjectURL(compressedFile);
        
        // 生成BlurHash
        const blurHash = await generateBlurHash(previewUrl);

        // 更新文件列表,新增blurHash字段
        setFiles(prev => [...prev, {
          id: index + prev.length, // 避免ID重复
          src: previewUrl,
          name: file.name,
          blurHash: blurHash
        }]);
      }
    },
  });

  return (
    <div {...getRootProps()}>
      <input {...getInputProps()} />
      <p>拖拽图片到这里,或点击选择</p>
      {/* 预览图片区域 */}
      {files.map(file => (
        <img key={file.id} src={file.src} alt={file.name} style={{ width: '100px', height: '100px', margin: '0 8px 8px 0' }} />
      ))}
    </div>
  );
};

export default YourUploadComponent;

3. 上传到服务器

后续上传时,把blurHash和图片文件一起发给服务器,比如用FormData:

const uploadToServer = async (files) => {
  for (const file of files) {
    const formData = new FormData();
    formData.append('image', file.src); // 或传实际的compressedFile,根据你的上传逻辑调整
    formData.append('blurHash', file.blurHash);
    // 发送请求
    await fetch('/api/upload', {
      method: 'POST',
      body: formData
    });
  }
};

4. 在Next.js中使用动态图片的BlurHash

从服务器拿到图片数据后,直接在Next.js的Image组件里用:

import Image from 'next/image';

const DynamicImage = ({ src, blurHash }) => {
  return (
    <Image
      src={src}
      alt="动态图片"
      width={600}
      height={400}
      placeholder="blur"
      blurHash={blurHash} // Next.js 13+直接支持该属性
    />
  );
};

关键提示

  • blurhash库是纯前端实现,完全在浏览器里运行,不用依赖任何外部服务。
  • 生成Hash时缩小图片尺寸能大幅提升性能,因为BlurHash只需要低分辨率的像素信息。
  • 组件数(encode函数的第4、5个参数)可按需调整,4x4是比较均衡的选择。

内容的提问来源于stack exchange,提问作者Mohammed Bekele

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.02 19:41:05