微信小程序开发之图片压缩方案

简介: 微信小程序开发之图片压缩方案

 目录

前言:

问题:现有的压缩方案支付宝小程序不生效

解决方案:

uni.createCanvasContext(canvasId, this)

核心代码展示:

1,封装公用工具类compressImage.js

2,html调用并上传服务器:

小结:


前言:

由于公司业务拓展,急需基于uniapp生成支付宝小程序。之前已经成功将微信小程序和H5融合成一套码,故得知此需求的时候,笔者信心十足,但是本着实践出真知的想法,觉得还是得先调研一下uniapp在支付宝小程序的兼容性,并集成已有项目主体关键功能,为后续的技术调研方案做准备。在调研过程中,发现之前封装好的图片压缩方法在支付宝小程序上无法正常使用,重新阅读了官方文档后,又双更新了项目的图片压缩方法的使用流程。

问题:现有的压缩方案支付宝小程序不生效

之前封装好的压缩方案,原理是使用canvas现实的,但是在支付宝小程序端不生效,canvas相关的api存在但是不可用。

解决方案:

查阅文档后,给canvas添加了id区分支付宝小程序,可兼容之。

以下是官方文档原文

uni.createCanvasContext(canvasId, this)

#定义

画布表示,传入定义在 <canvas/> 的 canvas-id或id(支付宝小程序是id、其他平台是canvas-id)

核心代码展示:

1,封装公用工具类compressImage.js

/**
 * 给的文件资源是否小于LimitSize (M), 小于走lessCallBack, 大于走moreCallBack
 */
export function imageSizeIsLessLimitSize(imagePath, limitSize, lessCallBack, moreCallBack) {
  uni.getFileInfo({
    filePath: imagePath,
    success(res) {
      console.log('压缩前图片大小:', res.size / 1024, 'kb')
      if (res.size > 1024 * 1024 * limitSize) {
        moreCallBack()
      } else {
        lessCallBack()
      }
    }
  })
} // 主调用方法
/**
 * 获取小于限制大小的Image, limitSize默认为1M,递归调用。
 */
export function getLessLimitSizeImage(canvasId, imagePath, limitSize = 1, drawWidth, callBack) {
  imageSizeIsLessLimitSize(
    imagePath,
    limitSize,
    (lessRes) => {
      callBack(imagePath)
    },
    (moreRes) => {
      uni.getImageInfo({
        src: imagePath,
        success: function(imageInfo) {
          var maxSide = Math.max(imageInfo.width, imageInfo.height) //画板的宽高默认是windowWidth
          var windowW = drawWidth
          var scale = 1
          if (maxSide > windowW) {
            scale = windowW / maxSide
          }
          var imageW = Math.floor(imageInfo.width * scale)
          var imageH = Math.floor(imageInfo.height * scale)
          console.log('调用压缩', imageW, imageH)
          getCanvasImage(canvasId, imagePath, imageW, imageH, (pressImgPath) => {
            getLessLimitSizeImage(canvasId, pressImgPath, limitSize, drawWidth * 0.7, callBack)
          })
        }
      })
    }
  )
}
/**
 * 获取画布图片
 */
export function getCanvasImage(canvasId, imagePath, imageW, imageH, getImgsuccess) {
  const ctx = uni.createCanvasContext(canvasId)
  ctx.drawImage(imagePath, 0, 0, imageW, imageH)
  ctx.draw(false, () => {
    uni.canvasToTempFilePath({
      canvasId: canvasId,
      x: 0,
      y: 0,
      width: imageW,
      height: imageH,
      quality: 1,
      success(res) {
        getImgsuccess(res.tempFilePath)
      }
    })
  })
}
export default {
  getLessLimitSizeImage,
  imageSizeIsLessLimitSize,
  getCanvasImage
}

image.gif

2,html调用并上传服务器:

<template>
  <view class="upload-page">
    <view class="upload-tips">您最多可上传{{maxCount}}张图片</view>
    <view class="image-list">
      <view v-for="(item, index) in fileList"
            :key="index"
            class="image-item">
        <image class="image"
               mode="aspectFit"
               :src="item.path"
               @click="viewImage(index)"></image>
        <image class="image-delete"
               :src="imgUrl + 'doctor/img_delete.png'"
               @tap.stop="deleteImage"
               :data-index="index"></image>
      </view>
      <view v-if="fileList.length < maxCount"
            class="image-item"
            @tap="openAlbum">
        <image class="image"
               :src="imgUrl + 'doctor/img_add.png'"></image>
      </view>
    </view>
    <view class="upload-btn"
          @tap="confirmUpload">确定</view>
    <canvas canvas-id="pressCanvas"
            id="pressCanvas"
            class="press-canvas"></canvas>
  </view>
</template>
<script>
import { getLessLimitSizeImage } from './compressImage.js'
export default {
  data() {
    return {
      imgUrl: process.env.VUE_APP_RESOURCE_URL,
      page: {
        json: {}
      },
      type: '',
      fileList: [],
      maxCount: 9
    }
  },
  components: {},
  props: {},
  onLoad(options) {
    this.type = options.type
    this.page.json = options
  },
  methods: {
    confirmUpload() {
      if (this.fileList.length === 0) {
        this.$util.showToast('请至少选择一张图片')
        return false
      }
      this.$Router.back()
      uni.$emit(this.page.json.emit, this.fileList)
    },
    // 查看图片
    viewImage(index) {
      let copyData = [],
        data = [].concat(this.fileList)
      data.forEach((v) => {
        copyData.push(v.path)
      })
      uni.previewImage({
        current: copyData[index],
        urls: copyData
      })
    },
    // 删除图片
    deleteImage(e) {
      let { index } = e.currentTarget.dataset
      this.fileList.splice(index, 1)
    },
    // 打开相册
    openAlbum() {
      let length = this.maxCount - this.fileList.length
      uni.chooseImage({
        count: length,
        sizeType: ['original', 'compressed'],
        sourceType: ['album', 'camera'],
        success: (res) => {
          this.upLoadImgs(res.tempFilePaths, this.type)
        }
      })
    },
    // 上传多张图片
    upLoadImgs(files, type) {
      uni.showLoading()
      let promises = files.map((item) => {
        return this.uploadImg(item, type)
      })
      Promise.all(promises)
        .then((datas) => {
          // 所有上传完成后
          this.fileList = datas.length > 0 && this.fileList.concat(datas)
          uni.hideLoading()
        })
        .catch(() => {
          uni.hideLoading()
        })
    },
    // 上传图片
    uploadImg(file, type) {
      return new Promise((resolve, reject) => {
        getLessLimitSizeImage('pressCanvas', file, 1, 750, (imagePath) => {
          /* #ifdef H5 */
          let devicetype = 'h5'
          /* #endif */
          /* #ifdef MP-WEIXIN */
          let devicetype = 'applet'
          /* #endif */
          /* #ifdef MP-ALIPAY */
          let devicetype = 'alipay'
          /* #endif */
          uni.uploadFile({
            url: process.env.VUE_APP_API_URL + 'client/v1/file/images',
            header: {
              'access-token': this.$store.state.user.accessToken,
              version: process.env.VUE_APP_VERSION,
              'version-code': process.env.VUE_APP_VERSION_CODE,
              devicetype: devicetype
            },
            fileType: 'image',
            filePath: imagePath,
            name: 'file',
            formData: {
              source: 'inquiryApply',
              type:  ''
            },
            success: (res) => {
              let image = JSON.parse(res.data)
              console.log('uploadFile success:', image)
              if (image.code === 200) {
                resolve(image.data[0])
              } else {
                this.$util.showModal(image.msg || '图片上传失败')
                reject(image)
              }
            },
            fail: (err) => {
              console.log('uploadFile fail:', JSON.stringify(err || {}))
              if (err.hasOwnProperty('errMsg') && err.errMsg.indexOf('timeout') > 0) {
                this.$util.showModal('上传超时,请稍后再试')
              } else {
                this.$util.showModal('图片上传失败,请稍后再试')
              }
              reject(err)
            },
            complete: () => {}
          })
        })
      })
    }
  }
}
</script>
<style lang="scss" scoped>
.upload-page {
  position: relative;
  width: 750rpx;
  height: 100vh;
  background-color: #ffffff;
}
.upload-tips {
  width: 750rpx;
  height: 80rpx;
  background-color: #fffbe8;
  font-size: 28rpx;
  color: #ed6a0c;
  line-height: 80rpx;
  text-align: center;
}
.image-list {
  box-sizing: border-box;
  display: flex;
  flex-wrap: wrap;
  justify-content: flex-start;
  align-items: center;
  width: 750rpx;
  padding: 30rpx;
}
.image-item {
  position: relative;
  box-sizing: border-box;
  width: 210rpx;
  height: 210rpx;
  margin-right: 30rpx;
  margin-bottom: 30rpx;
  border: 1rpx solid #ebedf0;
}
.image-item:nth-child(3n) {
  margin-right: 0;
}
.image-item .image {
  width: 210rpx;
  height: 210rpx;
}
.image-item .image-delete {
  position: absolute;
  top: -30rpx;
  right: -30rpx;
  width: 40rpx;
  height: 40rpx;
  padding: 10rpx;
}
.upload-btn {
  position: fixed;
  bottom: 0;
  left: 0;
  width: 750rpx;
  height: 100rpx;
  background-color: $primary;
  font-size: 30rpx;
  color: #ffffff;
  line-height: 100rpx;
  text-align: center;
}
.press-canvas {
  position: absolute;
  top: -1000px;
  left: -1000px;
  background-color: gray;
  width: 750px;
  height: 750px;
}
</style>

image.gif

小结:

以上就是笔者分享的图片压缩上传的方法封装及使用啦,完美兼容支付宝小程序,微信小程序及H5三端。希望对大家有所帮助。如有错误希望各位大神多多指教。

image.gif编辑

目录
相关文章
|
9月前
|
人工智能 小程序 前端开发
一个小程序轻量AR体感游戏,开发实现解决方案
针对青少年运动兴趣不足问题,AR体感游戏凭借沉浸式互动体验脱颖而出。结合小程序“AI运动识别”插件与WebGL渲染技术,可实现无需外设的轻量化AR健身游戏,如跳糕、切水果等,兼具趣味性与锻炼效果,适用于儿童健身及职工团建,即开即玩,低门槛高参与。
|
9月前
|
运维 小程序 数据可视化
小程序开发平台有哪些?SaaS小程序制作平台哪个好
小程序开发模式详解:自主开发、SaaS小程序制作平台与外包全对比 选择合适的小程序开发模式,是项目成功的基石。这三种模式在成本、周期、控制力和灵活性上各有千秋,适用于不同阶段和不同类型的企业。下面我们将逐一深入剖析。
777 9
|
9月前
|
移动开发 小程序 前端开发
小程序开发平台有哪些?哪个好
小程序的开发方式丰富多元,开发团队可根据自身的技术背景、项目具体需求以及资源状况,灵活挑选最为适宜的开发路径。以下将详细介绍几种主流的小程序开发方式。
712 1
|
9月前
|
移动开发 小程序 前端开发
小程序快速开发平台有哪些?
小程序开发并非“一刀切”,需结合技术储备、资金预算、时间规划及功能需求等多维度因素综合考量。以下为您详细拆解五种主流开发方案及其适用场景,助您精准匹配开发路径。
508 3
|
10月前
|
消息中间件 人工智能 Java
抖音微信爆款小游戏大全:免费休闲/竞技/益智/PHP+Java全筏开源开发
本文基于2025年最新行业数据,深入解析抖音/微信爆款小游戏的开发逻辑,重点讲解PHP+Java双引擎架构实战,涵盖技术选型、架构设计、性能优化与开源生态,提供完整开源工具链,助力开发者从理论到落地打造高留存、高并发的小游戏产品。
|
9月前
|
移动开发 小程序 前端开发
小程序开发平台有哪些?小程序开发制作软件推荐
小程序开发方案全解析:5种主流方式与选择指南 小程序开发需根据技术能力、预算、时间及功能需求综合决策。以下为5种主流开发方案及适用场景分析:
26451 0
|
小程序 前端开发 Android开发
小程序微信分享功能如何开发?开放平台已绑定仍不能使用的问题?-优雅草卓伊凡
小程序微信分享功能如何开发?开放平台已绑定仍不能使用的问题?-优雅草卓伊凡
2550 29
小程序微信分享功能如何开发?开放平台已绑定仍不能使用的问题?-优雅草卓伊凡
|
11月前
|
小程序 JavaScript API
uni-halo + 微信小程序开发实录:我的第一个作品诞生记
这篇文章介绍了使用uni-halo框架进行微信小程序开发的过程,包括选择该框架的原因、开发目标以及项目配置和部署的步骤。
574 0
uni-halo + 微信小程序开发实录:我的第一个作品诞生记