uniapp预览本地图片

问题

在 uniapp 中使用 uni.previewImage 预览项目内的本地图片时,直接传入 static 目录下的图片路径无法正常预览:

uni.previewImage({
  urls: ['/static/example.png']
})

因此需要先将本地图片读取并转换为 Base64,再将转换后的数据传递给 uni.previewImage

解决方案

将图片转换封装成一个跨端函数。微信小程序端使用 uni.getFileSystemManager().readFile 读取文件并转换为 Base64;H5 端则通过 Image + Canvas 获取 Base64 数据。

同时统一使用 Promise 处理异步流程,避免回调与 Promise 混用。

/**
 * 图片 MIME Type 映射
 *
 * Base64 图片除了需要编码后的数据,还需要携带正确的 MIME Type。
 * 例如 PNG 图片应使用:
 *
 * data:image/png;base64,...
 */
const MIME_TYPES: Record<string, string> = {
  png: 'image/png',
  jpg: 'image/jpeg',
  jpeg: 'image/jpeg',
  webp: 'image/webp',
  gif: 'image/gif'
}

/**
 * 将本地图片转换为 Base64
 *
 * @param filePath 图片路径
 * @returns Promise<string> Base64 图片数据
 */
export function imageToBase64(filePath: string): Promise<string> {
  return new Promise((resolve, reject) => {
    // #ifdef MP-WEIXIN

    /**
     * 微信小程序可以通过文件系统 API 直接读取本地图片。
     *
     * encoding 设置为 base64 后,readFile 返回的 data
     * 就是图片经过 Base64 编码后的字符串。
     */
    uni.getFileSystemManager().readFile({
      filePath,
      encoding: 'base64',

      success: ({ data }) => {
        /**
         * 根据文件扩展名确定图片类型。
         *
         * 不能简单地将所有图片都声明为 image/jpeg,
         * 否则实际文件类型与 MIME Type 可能不一致。
         */
        const extension =
          filePath.split('.').pop()?.toLowerCase() || ''

        const mimeType = MIME_TYPES[extension] || 'image/jpeg'

        /**
         * 拼接成标准 Data URL:
         *
         * data:image/png;base64,xxxxxx
         *
         * 这种格式可以直接作为图片地址使用。
         */
        resolve(`data:${mimeType};base64,${data}`)
      },

      // 文件读取失败时直接向外抛出异常
      fail: reject
    })

    // #endif

    // #ifdef H5

    /**
     * H5 环境无法使用微信小程序的文件系统 API,
     * 因此通过 Image 加载图片,再借助 Canvas 导出 Base64。
     */
    const image = new Image()

    // 图片加载完成后,将图片绘制到 Canvas
    image.onload = () => {
      const canvas = document.createElement('canvas')
      const context = canvas.getContext('2d')

      // 无法获取 Canvas Context 时终止转换
      if (!context) {
        reject(new Error('无法创建 Canvas Context'))
        return
      }

      // 使用图片的原始尺寸,避免转换过程中改变图片尺寸
      canvas.width = image.naturalWidth
      canvas.height = image.naturalHeight

      // 将图片绘制到 Canvas
      context.drawImage(image, 0, 0)

      // 导出 Base64 数据
      resolve(canvas.toDataURL())
    }

    // 图片加载失败
    image.onerror = () => {
      reject(new Error('图片加载失败'))
    }

    // 开始加载图片
    image.src = filePath

    // #endif
  })
}

使用时直接将转换后的 Base64 传递给 uni.previewImage

/**
 * 预览本地图片
 *
 * @param filePath 图片路径
 */
export async function previewLocalImage(filePath: string) {
  const base64 = await imageToBase64(filePath)

  uni.previewImage({
    urls: [base64],
    current: 0,
    loop: true
  })
}

这样可以将项目内的本地图片统一转换成 uni.previewImage 可以直接处理的 Base64 数据。

posted @ 2026-08-20 16:47  Syinho  阅读(7)  评论(0)    收藏  举报