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

一、实现原理

  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,
    });
  },
});

三、效果演示

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

此处选择了从相册选择




相关推荐
用户059540174461 小时前
把AI对话记忆存储测试从手工改成Playwright+pytest,覆盖率从20%提到96%,回归时间缩短90%
前端·css
kyriewen1 小时前
别再这样写TypeScript了——Code Review中最常见的8个反模式
前端·javascript·typescript
名字还没想好☜1 小时前
Next.js ‘use client‘ 到底加在哪:Server/Client Components 边界与常见报错
开发语言·前端·javascript·react·next.js
午安~婉2 小时前
GitHub Token/ GitHub Stats统计显示图异常
前端·github·vercel·github token
码云之上2 小时前
AI Agent 工程化总览篇:从 Prompt 到 Harness
前端·人工智能
2501_926978332 小时前
以说明书 DNA 为模板——完整 AGI 的结构图景
前端·人工智能·经验分享·笔记·ai写作
IT_陈寒2 小时前
Vite静态资源引用这个坑我踩得有点疼
前端·人工智能·后端
程序员黑豆3 小时前
鸿蒙应用开发:AttributeModifier 使用教程
前端·harmonyos
codeniu3 小时前
TRAE Work 实战 | 从"有个想法"到线上Demo,我全程只靠对话就完成了
前端·trae
妙码生花3 小时前
从 PHP 到 AI + Golang,程序员自救转型手记(五十):增加管理员角色组管理
前端·后端·ai编程