微信原生实现一个简易的图片上传功能

一、实现原理

  1. wx.showActionSheet():显示操作菜单,选择是从相册选择还是相机拍摄照片
  2. wx.chooseImage():从本地相册选择图片或使用相机拍照。
  3. wx.uploadFile():将本地资源上传到服务器。客户端发起一个 HTTPS POST 请求,其中 content-type 为 multipart/form-data。
  4. wx.previewMedia(): 预览图片和视频。

二、代码

upload.wxml

html 复制代码
<view class="study-title">图片上传原理</view>
<view class="show-img-box">
    <view class="img-item-box" wx:for="{{imgList}}" wx:key="*this" data-src="{{item}}" data-src-list="{{imgList}}" bindtap="clickImg">
        <image class="img-item" src="{{item}}" />
    </view>
    <view class="upload" bindtap="chooseImgType">
        <view class="img-upload"></view>
    </view>
</view>

upload.wxss

css 复制代码
/* pages/upload/upload.wxss */
.study-title {
  width: 100vw;
  margin: 50rpx 0;
  font-size: 40rpx;
  font-weight: 800;
  text-align: center;
}
.show-img-box {
  width: 600rpx;
  display: flex;
  flex-wrap: wrap;
  margin: 0 auto;
}

.img-item-box {
  width: 184rpx;
  height: 184rpx;
  margin: 4px;
  background-color: #ccc;
}

.img-item {
    width: 184rpx;
    height: 184rpx;
}
.upload {
  margin: 4px;
  width: 184rpx;
  height: 184rpx;
  background: rgba(203, 224, 208, 0.5);
  border-radius: 5rpx;
  display: flex;
  align-items: center;
  justify-content: center;
}
.img-upload {
  width: 120rpx;
  height: 120rpx;
  background-image: url(https://pro-core.babycdn.com/2021/aosmith/lottery/images2020/watersystem/case/robot/img_upload.png);
  background-repeat: no-repeat;
  background-size: cover;
}

upload.js

javascript 复制代码
// pages/upload/upload.js
Page({
  /**
   * 页面的初始数据
   */
  data: {
    imgList: [],  // 由于没有可用的服务器域名,因此定义此数据用于展示上传的图片,以演示图片预览功能
    imgFilePaths: [], // 上传的图片存放路径,有可用的服务器域名用此数据渲染
    showSelect: false, // 是否显示选择框
    host: "https://5blog.com/Api", // 服务器域名,此处为错误域名
  },
  // 弹出操作菜单,选择获取图片的方式
  chooseImgType() {
    // 显示操作菜单
    wx.showActionSheet({
      itemList: ["从相册选择", "拍照"],
      success: (res) => {
        if (res.tapIndex == 0) {
          this.chooseImg("album");
        } else if (res.tapIndex == 1) {
          this.chooseImg("camera");
        }
      },
    });
  },
  // 选择图片
  chooseImg(type) {
    let { imgFilePaths } = this.data;
    wx.chooseImage({
      // 从本地相册选择照片或使用相机拍照
      count: 9, // 最多可以选择的图片张数, 默认9
      sizeType: ["original", "compressed"], // 所选图片的尺寸,默认原图和压缩图都可以
      sourceType: [type], // 选择图片的来源,默认相册和相机都可以
      success: async (res) => {
        // 接口调用成功的回调
        // console.log("res", res);
        // res.tempFilePaths是临时文件路径数组,数组内的元素可以直接作为src使用
        const tempFilePaths = res.tempFilePaths;
        this.setData({
          imgList: res.tempFilePaths,
        });
        let tempLength = 9 - imgFilePaths.length;
        let tempFilePaths_ = tempFilePaths.splice(0, tempLength);
        // 得到所有上传成功后的图片url组成的数组
        let imgUrlArr = await Promise.all(
          // 实现上传所有图片到服务器
          tempFilePaths_.map((item, index) => {
            // 返回每张图片的上传结果
            return this.updateImg(item, index);
          })
        );
        console.log("imgUrlArr", imgUrlArr);
        // 根据需求补充其他内容
      },
      fail: (err) => {
        console.log(type);
        // 接口调用失败的回调
        console.log("图片选取上传错误", err);
      },
      complete: () => {
        // 接口调用结束的回调(调用成功、失败都会执行)
      },
    });
  },
  // 实现将单张图片上传服务器,上传成功返回图片url,上传失败返回false
  updateImg(src, index = 0) {
    wx.showLoading({
      title: "上传中...",
      mask: true,
    });
    // 将本地资源上传到服务器接口,客户端发起一个post请求
    // 其中content-type为multipart/form-data
    return new Promise((resolve, reject) => {
      wx.uploadFile({
        url: this.data.host + "/Attach/Index/upload", // 开发者服务器地址
        filePath: src, // 要上传文件资源的路径(本地路径)
        header: {
          "content-type": "multipart/form-data", // 默认值
        },
        name: "img", // 文件对应的key,开发者在服务端通过这个key获取文件的二进制内容
        formData: {
          // http请求中其他额外的form data
          type: "image",
          index: index,
        },
        // 上传成功的回调
        success: function (res) {
          console.log("res", res);
          if (res && res.data && !res.data.error) {
            let img = JSON.parse(res.data);
            resolve(img.data);
          } else {
            wx.showToast({
              title: "图片提交失败",
              icon: "none",
              duration: 1500,
            });
            resolve(false);
          }
        },
        complete: function (res) {
          wx.hideLoading();
        },
      });
    });
  },
  // 实现图片预览
  clickImg(e) {
    let src = e.currentTarget.dataset.src;
    let sources = e.currentTarget.dataset.srcList;
    console.log(sources);
    sources = sources.map((item) => {
      return {
        url: item, // 链接
        type: "image", // 默认类型是图片
      };
    });
    // 预览图片和视频接口
    wx.previewMedia({
      sources: sources,
    });
  },
});

三、效果演示

这里进行了真机调试 以演示以上代码的实际运行效果。

此处选择了从相册选择




相关推荐
ywf12151 小时前
前端的dist包放到后端springboot项目下一起打包
前端·spring boot·后端
恋猫de小郭1 小时前
2026,Android Compose 终于支持 Hot Reload 了,但是收费
android·前端·flutter
hpoenixf7 小时前
2026 年前端面试问什么
前端·面试
还是大剑师兰特7 小时前
Vue3 中的 defineExpose 完全指南
前端·javascript·vue.js
泯泷7 小时前
阶段一:从 0 看懂 JSVMP 架构,先在脑子里搭出一台最小 JSVM
前端·javascript·架构
2501_933907218 小时前
宁波小程序开发服务与技术团队专业支持
科技·微信小程序·小程序
mengchanmian8 小时前
前端node常用配置
前端
华洛8 小时前
利好打工人,openclaw不是企业提效工具,而是个人助理
前端·javascript·产品经理
xkxnq9 小时前
第六阶段:Vue生态高级整合与优化(第93天)Element Plus进阶:自定义主题(变量覆盖)+ 全局配置与组件按需加载优化
前端·javascript·vue.js
A黄俊辉A9 小时前
vue css中 :global的使用
前端·javascript·vue.js