小程序开发攻略:如何优雅地实现图片上传?

前言

随着微信小程序的普及,图片上传已成为许多开发者关注的重点。在本文中,我们将探讨如何实现微信小程序的图片上传功能,帮助大家更好地应对开发中的挑战。


实现思路

首先我们需要定义一个存放图片的数组,通过方法拿取图片的详细信息,然后调用微信小程序的 wx.uploadFile 方法将拿到的图片信息添加到定义好的图片数组中即可;删除图片我们只需要拿到存放图片的数组再通过 splice 方法删除。

wx.uploadFile(Object object) 方法的参数:

属性类型必填项说明
urlstring开发者服务器地址
filePathstring要上传文件资源的路径 (本地路径)
namestring文件对应的 key,开发者在服务端可以通过这个 key 获取文件的二进制内容
headerObjectHTTP 请求 Header,Header 中不能设置 Referer
formDataObjectHTTP 请求中其他额外的 form data
timeoutfunction超时时间,单位为毫秒
successfunction接口调用成功的回调函数
failfunction接口调用失败的回调函数
completefunction接口调用结束的回调函数(调用成功、失败都会执行)

源码文件

wxml文件

<view class="imgBox">
    <view><text>车辆照片</text></view>
    <view class="imgContant">
        <van-uploader accept="image" max-count="1" bind:after-read="afterRead" bind:delete="deleteClick" file-list="{{ fileList }}" />
    </view>
</view>

js文件

//获取应用实例
var app = getApp();
Page({
    data: {
        fileList: [], //图片存放的数组
    },
    // 删除照片
    deleteClick(event) {
        var imgData = this.data.fileList;
        // 通过splice方法删除图片
        imgData.splice(event.detail.index, 1);
        // 更新图片数组
        this.setData({
            fileList: imgData
        })
    },
    // 车辆照片
    afterRead(event) {
        // loading加载
        wx.showLoading({
            title: '上传中...'
        });
        const {file} = event.detail;//获取图片详细信息
        let that = this;//防止this指向问题
        // 设置请求头,根据项目需求变换
        let Authorization = wx.getStorageSync('key')
        let headers = {
            'content-type': '',
            'client_id': 'webApp',
            'client_secret': '123456',
        }
        if (Authorization) {
            headers.Authorization = 'Bearer ' + Authorization
        }
        // 调用wx.uploadFile上传图片方法
        wx.uploadFile({
            url: "ip" + "url",
            method: 'POST',
            header: headers,
            filePath: file.url,
            name: 'file',
            formData: {
                user: 'test'
            },
            // 成功回调
            success(res) {
                // JSON.parse()方法是将JSON格式字符串转换为js对象
                var result = JSON.parse(res.data);
                // 上传完成需要更新 fileList
                const {fileList = []} = that.data;
                // 将图片信息添加到fileList数字中
                fileList.push({
                    ...file,
                    url: result.data
                });
                // 更新存放图片的数组
                that.setData({
                    fileList
                });
                wx.hideLoading();//停止loading
            },
        });
    },
})

wxss文件

page {
    background: #EFF4FF;
}

.imgBox {
    font-size: 28rpx;
    margin: 3%;
    background: white;
    padding: 30rpx;
    border-radius: 30rpx;
    display: flex;
    align-items: center;
}

.imgContant {
    margin-left: 40rpx;
}

实现效果

在这里插入图片描述


进阶 – 封装公共上传、删除方法

上面的实例只是单个的上传,那如果我们遇到几十个需要上传的内容,就要写几十个上传的方法和删除的方法,显然是不太合适的,所以当上传内容比较多时,我们可以将其封装成一个公共的上传、删除方法,通过传递不同的参数去调用这个方法。

wxml文件

<view>
    <van-uploader max-count="1" bind:after-read="uploadingsOn" bind:delete="removesOn" data-file-list-key="fileListOne" data-form-key="imgUrlOne" file-list="{{ fileListOne }}" />
</view>
<view>
    <van-uploader max-count="3" bind:after-read="uploadingsOn" bind:delete="removesOn" data-file-list-key="fileListTwo" data-form-key="imgUrlTwo" file-list="{{ fileListTwo }}" />
</view>
<button bindtap="submit">提交</button>

js文件

var app = getApp()
Page({
    data: {
        fileListOne: [], // 第一个文件列表
        fileListTwo: [], // 第二个文件列表
        form: {
            imgUrlOne: [], // 第一个文件列表对应的表单数据
            imgUrlTwo: [], // 第二个文件列表对应的表单数据
        }
    },
    // 上传文件
    uploadFile(filePath, successCallback, fileListKey, formKey) {
        wx.showLoading({
            title: '上传中...'
        });
        wx.uploadFile({
            url: app.API_URL + "yourUrl",
            method: 'POST',
            filePath: filePath,
            name: 'file',
            success(res) {
                var result = JSON.parse(res.data);
                successCallback(result, fileListKey, formKey);
                wx.hideLoading();
            },
        });
    },
    // 删除文件
    deleteFile(index, fileList, formKey) {
        var imgData = [...fileList];
        imgData.splice(index, 1);
        var form = {
            ...this.data.form
        };
        form[formKey].splice(index, 1); // 删除对应表单数据
        return {
            fileList: imgData,
            form: form
        };
    },
    // 统一删除文件事件处理函数
    removesOn(event) {
        const index = event.detail.index;
        const fileListKey = event.currentTarget.dataset.fileListKey;
        const formKey = event.currentTarget.dataset.formKey;
        const {
            fileList,
            form
        } = this.deleteFile(index, this.data[fileListKey], formKey);
        this.setData({
            [fileListKey]: fileList,
            form: form
        });
    },
    // 统一上传文件事件处理函数
    uploadingsOn(event) {
        let that = this;
        if (that.beforeRead(event)) {
            const {
                file
            } = event.detail;
            const fileListKey = event.currentTarget.dataset.fileListKey;
            const formKey = event.currentTarget.dataset.formKey;
            this.uploadFile(file.url, function (result, fileListKey, formKey) {
                const fileList = that.data[fileListKey];
                fileList.push({
                    ...file,
                });
                const form = that.data.form;
                form[formKey].push(app.FILE_URL + result.map.path); // 添加上传后的地址到表单数据
                that.setData({
                    [fileListKey]: fileList,
                    form: form
                });
                wx.hideLoading();
            }, fileListKey, formKey);
        }
    },
    // 校验图片格式
    beforeRead(file) {
        if (!/(jpg|jpeg|png|JPG|PNG)/i.test(file.detail.file.url)) {
            wx.showToast({
                title: '请上传正确格式的图片',
                icon: 'none',
            })
            return false
        }
        return true
    },
    // 提交表单
    submit() {
        // 数组的形式
        console.log(this.data.form);
        console.log(this.data.fileListOne, this.data.fileListTwo);
        // // 将数组转换为逗号分隔的字符串
        // const form = { ...this.data.form };
        // form.imgUrlOne = form.imgUrlOne.join(","); 
        // form.imgUrlTwo = form.imgUrlTwo.join(","); 
        // console.log(form);
    },
})

拓展1 – 压缩图片

当涉及到图片的上传时,图片压缩是一个非常重要的话题。随着手机摄像头和相机的不断进步,我们能够拍摄到更高分辨率的照片,但同时也面临着更大的图片文件大小和传输速度的挑战。过大的图片文件会导致网页加载缓慢,增加用户等待时间,甚至可能耗尽用户的流量。因此,我们需要一种方法优化压缩图片的大小。『点此查看官方文档』

utils/imageUtils.js 文件

// 图片压缩方法
function compressImage(filePath) {
  return new Promise((resolve, reject) => {
    wx.getFileSystemManager().getFileInfo({
      filePath,
      success(res) {
        const fileSize = res.size / 1024 / 1024; // 文件大小,单位MB
        if (fileSize > 10) {
          console.log(fileSize,"文件大于10MB,需要进行压缩");
          // 如果文件大于10MB,需要进行压缩
          wx.compressImage({
            src: filePath,
            quality: 20, // 压缩质量
            success(res) {
              resolve(res.tempFilePath);
            },
            fail(err) {
              reject(err);
            },
          });
        } else {
          // 如果文件小于等于10MB,直接返回原文件路径
          resolve(filePath);
        }
      },
      fail(err) {
        reject(err);
      },
    });
  });
}

module.exports = {
  compressImage,
};

app.js 文件

const imageUtils = require('./utils/imageUtils');//图片压缩
App({
  imageUtils,
  onLaunch: function () {},
  globalData: {
    userInfo: null,
  },
});

任意文件使用

var app = getApp()
 // 上传文件
uploadFile(filePath, successCallback, fileListKey, formKey) {
    wx.showLoading({
        title: '上传中...'
    });
    app.imageUtils.compressImage(filePath).then((compressedFilePath) => {
        wx.uploadFile({
            url: app.API_URL + "yourUrl",
            method: 'POST',
            filePath: compressedFilePath,
            name: 'file',
            success(res) {
                var result = JSON.parse(res.data);
                successCallback(result, fileListKey, formKey);
                wx.hideLoading();
            },
        });
    })
},

拓展2 – 回显缓存图片

使用场景:用户填写表单到一半时,因为操作不当或者其它原因退出表单,当用户再次进入表单,需要回显用户上一次填写表单的内容。

Page({
  data: {
    idCardImg: [], // 存储身份证图片数据的数组
    frontImg: [], // 存储正面照片数据的数组
    tailImg: [], // 存储背面照片数据的数组
  },
  onLoad() {
    // 在页面加载时,检查本地存储是否存在特定数据,并进行回显
    const keys = ['idCardImg', 'frontImg', 'tailImg'];
    keys.forEach(key => this.setIfStorageExists(key));
  },
  // 图片回显方法
  setIfStorageExists(key) {
    const storageData = wx.getStorageSync(key); // 从本地存储中获取指定键的数据
    if (storageData) {
      this.setData({
        [key]: storageData // 将获取到的数据设置到对应的数据属性中
      });
    }
  },
})

图片缓存代码逻辑

// 统一删除文件事件处理函数
removesOn(event) {
    // ... 之前代码不变
    // 删除对应的浏览器存储
    wx.setStorageSync(fileListKey, fileList);
},
// 统一上传文件事件处理函数
uploadingsOn(event) {
    if (that.beforeRead(event)) {
        // ... 之前代码不变
    	// 删除对应的浏览器存储
        // 图片缓存
        wx.setStorageSync(fileListKey, fileList);
        wx.hideLoading();
    }, fileListKey, formKey);
  }
},

相关推荐

element表格上传图片必看:如何避免全行上传?
vue开发者必看!基于element实现文件上传功能的完整教程
让图片上传变得更简单:vue和vant的完美融合

  • 26
    点赞
  • 129
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 15
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 15
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

水星记_

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值