vue + uni-app:利用原生uni.chooseImage封装拍照功能的组件

这是一个单独的拍照功能组件,作为子组件引入后可直接调用。

注意:1.上传图片成功后,需要在upload()函数将图片上传到自己的服务器,需要修改下参数和接口URL。2.重新加载的时候会从接口获取图片,需要在getImgList()函数修改为自己的接口地址。 这两处需要替换自己的服务器路径即可。

父组件中调用:

javascript 复制代码
<!-- 使用拍照/选图组件 -->
<view class="picker-wrapper">
	<PhotoPicker 
	  :maxCount="9" 
	  :sizeType="['original', 'compressed']"
	/>
</view>

import PhotoPicker from '@/components/PhotoPicker.vue'

拍照功能的组件:共8个函数 choosePhoto()、choosePhotoCore()、cameraCallback()、upload()、dataURItoBlob()、getImgList()、previewImage()、deleteImage()

javascript 复制代码
<template>
  <view class="photo-picker">
    <view class="image-preview-container">
      <!-- 遍历显示已选择的图片 -->
      <view class="image-item" v-for="(image, index) in imageList" :key="index">
        <!-- 图片预览 -->
        <image
          class="preview-image"
          :src="image"
          mode="aspectFill"
          @click="previewImage(index)"
        ></image>
        <!-- 删除按钮 -->
        <view class="delete-btn" @click.stop="deleteImage(index)">
          <text class="delete-icon">×</text>
        </view>
      </view>

      <!-- 添加图片按钮("+"号) -->
      <view
        class="add-image-btn"
        v-if="imageList.length < maxCount"
        @click="choosePhoto"
      >
        <text class="add-icon">+</text>
      </view>
    </view>
  </view>
</template>

<script>
export default {
  name: "PhotoPicker",
  props: {
    //最大选择数量,默认9张
    maxCount: {
      type: Number,
      default: 9,
    },
    sizeType: {
      type: Array,
      default: () => ["original", "compressed"], //图片压缩类型  original:原图  compressed:压缩图
    },
  },
  data() {
    return {
      imageList: [], //图片列表
    };
  },
  methods: {
    choosePhoto() {
      const that = this;
      const remainCount = this.maxCount - this.imageList.length; //计算还能选择多少张图片

      if (remainCount <= 0) {
        uni.showToast({
          title: `最多只能选择${this.maxCount}张图片`,
          icon: "none",
          duration: 2000,
        });
        return;
      }
      that.choosePhotoCore(remainCount);
    },
    choosePhotoCore(remainCount) {
      const that = this;
      uni.chooseImage({
        sourceType: ["camera", "album"], //相机和相册
        sizeType: this.sizeType, //原图和压缩图
        count: remainCount, //可选择的最大数量(剩余可选数量)
        success: function (res) {
          console.log("选择图片成功:", res);

          const tempFilePaths = res.tempFilePaths; //获取上传的图片路径
          uni.showToast({
            title:
              tempFilePaths.length === 1
                ? "选择成功"
                : `已选择${tempFilePaths.length}张图片`,
            icon: "success",
            duration: 1500,
          });
          this.cameraCallback(tempFilePaths); //base64转换,将图片数据处理
        },
        fail: function (err) {
          console.log("选择图片失败:", err);
          uni.showToast({
            title: "选择失败,请检查权限",
            icon: "none",
            duration: 2000,
          });
        },
      });
    },
    //base64转换,将图片数据处理
    cameraCallback(b64Data, uri) {
      let uriData = null;
      uni.showLoading({
        title: "上传中...",
        mask: true,
      });
      //如果是uri路径,直接使用
      if (uri) {
        uriData = uri;
      } else {
        //如果是base64格式数据,处理为URI使用
        if (b64Data === "") {
          return;
        }
        let prefix = "data:image/jpeg;base64,";
        if (b64Data.startsWith("data")) {
          prefix = "";
        }
        let blob = this.dataURItoBlob(prefix + b64Data);
        uriData = URL.createObjectURL(blob);
      }
      let imgs = [
        {
          name: "file0",
          uri: uriData,
        },
      ];
      this.upload(imgs);
    },
    //上传至服务器
    upload(imgs) {
      var that = this;
      var url = "https://api.heliping.com/api/v1/file/upload"; //这块写自己的服务器接口,我这接口是个demo
      uni.uploadFile({
        url: url,
        files: imgs,
        formData: {},
        header: {
          Authorization: "Bearer " + uni.getStorageSync("access_token"),
        },
        success: (uploadFileRes) => {
          uni.hideLoading();
          uni.showToast({
            icon: "none",
            title: "上传成功",
          });
          that.getImgList(); //上传成功后,获取图片列表
        },
        fail: (uploadFileRes) => {
          uni.hideLoading();
          uni.showToast({
            icon: "none",
            title: "上传失败",
          });
        },
      });
    },
    //base64转为blob格式
    dataURItoBlob(base64Data) {
      var byteString;
      if (base64Data.split(",")[0].indexOf("base64") >= 0)
        byteString = atob(base64Data.split(",")[1]);
      //base64 解码
      else {
        byteString = unescape(base64Data.split(",")[1]);
      }
      var mimeString = base64Data.split(",")[0].split(":")[1].split(";")[0]; //mime类型 -- image/pn
      var ia = new Uint8Array(byteString.length); //创建视图
      for (var i = 0; i < byteString.length; i++) {
        ia[i] = byteString.charCodeAt(i);
      }
      var blob = new Blob([ia], {
        type: mimeString,
      });
      return blob;
    },
    getImgList() {
      var that = this;
      var url = this.appConfig.dev_url + "/xxxxxxxxx/file/fileList"; //获取图片列表接口
      var data = {
        xxxxx: "xxxxxx", //这块写自己的接口参数
      };
      var access_token = uni.getStorageSync("access_token");
      uni.request({
        url: url,
        method: "POST",
        data: data,
        header: {
          Authorization: "Bearer " + access_token,
          Accept: "application/json,text/plain,*/*",
        },
        success: (res) => {
          that.imageList = "xxxxxxxxx"; //这块获取图片列表
        },
      });
    },
    //图片预览
    previewImage(index) {
      uni.previewImage({
        current: index,
        urls: this.imageList, //这块的urls填写自己的图片路径
      });
    },

    //删除图片
    deleteImage(index) {
      const that = this;
      uni.showModal({
        title: "提示",
        content: "确定要删除这张图片吗?",
        success: function (res) {
          if (res.confirm) {
            that.imageList.splice(index, 1); //从列表中删除指定图片
            that.$emit("change", that.imageList);
            uni.showToast({
              title: "已删除",
              icon: "success",
              duration: 1500,
            });
          }
        },
      });
    },
  },
  mounted() {
    this.getImgList();
  },
};
</script>

<style lang="scss" scoped>
.photo-picker {
  width: 100%;
  box-sizing: border-box;
}
.image-preview-container {
  display: flex;
  flex-wrap: wrap;
  gap: 20rpx;
  padding: 20rpx;
}
.image-item {
  position: relative;
  width: 200rpx;
  height: 200rpx;
  border-radius: 12rpx;
  overflow: hidden;
  background-color: #f5f5f5;
  box-shadow: 0 2rpx 8rpx rgba(0, 0, 0, 0.1);
}
.preview-image {
  width: 100%;
  height: 100%;
  display: block;
}
.delete-btn {
  position: absolute;
  top: 8rpx;
  right: 8rpx;
  width: 48rpx;
  height: 48rpx;
  background-color: rgba(0, 0, 0, 0.6);
  border-radius: 50%;
  display: flex;
  align-items: center;
  justify-content: center;
  z-index: 10;
}
.delete-icon {
  color: #ffffff;
  font-size: 36rpx;
  font-weight: bold;
  line-height: 1;
}
.add-image-btn {
  width: 200rpx;
  height: 200rpx;
  border: 2rpx dashed #d0d0d0;
  border-radius: 12rpx;
  display: flex;
  align-items: center;
  justify-content: center;
  background-color: #fafafa;
  box-sizing: border-box;
  transition: all 0.3s ease;
}
.add-image-btn:active {
  background-color: #f0f0f0;
  border-color: #b0b0b0;
}
.add-icon {
  font-size: 80rpx;
  color: #d0d0d0;
  font-weight: 300;
  line-height: 1;
}
.image-preview-container:empty::before {
  content: "暂无图片";
  display: block;
  width: 100%;
  text-align: center;
  color: #999;
  font-size: 28rpx;
  padding: 40rpx 0;
}
</style>
相关推荐
天天向上vir2 小时前
防抖与节流
前端·typescript·vue
@AfeiyuO2 小时前
Vue3 饼图定制图
vue·echarts
计算机毕设指导62 小时前
基于微信小程序的旅游线路定制系统【源码文末联系】
java·spring boot·微信小程序·小程序·tomcat·maven·旅游
qq_12498707532 小时前
基于Spring Boot的微信小程序的智慧商场系统的设计与实现
java·spring boot·spring·微信小程序·小程序·毕业设计·计算机毕业设计
雪芽蓝域zzs2 小时前
uniapp 判断运行设备类型(安卓、苹果、鸿蒙、微信小程序、H5)
android·uni-app·harmonyos
2503_928411562 小时前
12.26 小程序代码片段【添加WeaUI内容】
前端·微信小程序·小程序
梦6502 小时前
UniApp 全面介绍与快速上手
uni-app
壹号机长3 小时前
uniapp+vue3 接入deepseek Ai
ai·小程序·uni-app
2501_915106323 小时前
iOS开发中CPU功耗监控的实现与工具使用
android·macos·ios·小程序·uni-app·cocoa·iphone