微信小程序实现自定义拍照、预览图片组件

           

需求:

1.当未拍摄任何照片或者预览相册中无照片时,不展示预览相册icon入口及提交按钮

2.图片预览页支持列表中点击删除icon删除,图片点击时全屏预览,预览中支持放大缩小、左右滑动切换列表中的图片,删除当前预览图片

3.列表中删除图片或预览时删除图片均需二次确认

4.点击图片预览时,导航栏显示当前预览图片索引/全部图片数量

 预览组件实现方法:

组合微信小程序movable-area、movable-view、swiper-item组件

视图容器 / movable-area (qq.com)

视图容器 / swiper (qq.com)

/pages/takePhoto

拍照页

<!--index.wxml-->


<view class="take-photo">
    <view class="content" wx:if="{{showCamera && loading}}">
        <camera device-position="back" flash="off" binderror="error" style="width: 100%; height: 100vh;"></camera>
        <view class="img-perview" wx:if="{{img}}">
            <image src="{{img}}" mode="widthFix"></image>
        </view>
        <view class="info" wx:if="{{infoShow}}">请拍摄上传文件</view>
        <!-- 图片预览 -->
        <view class="photo-album" bindtap="picturePreview" wx:if="{{imgList.length}}">
            <view class="iconfont icon-duozhaopian"></view>
            <view class="count-dot">{{imgList.length}}</view>
        </view>
        <!-- 拍照 -->
        <view class="btn">
            <view class="circular" catchtap="takePhoto">
                <view class="iconfont icon-paizhao"></view>
            </view>
        </view>
        <!-- 提交 -->
        <van-button block type="primary" disabled="{{isSubmitting}}"  custom-class="submit-btn" bind:click="submit" wx:if="{{imgList.length}}">
            提交
        </van-button>
    </view>
    <view class="err" wx:if="{{!showCamera && loading}}">相机启动失败</view>
    <!-- 上传toast -->
    <van-popup show="{{ toastShow }}" overlay-style="background: rgba(0,0,0,0.6);" custom-style="background:transparent">
        <view class="toast-content">
        <view class="icon">
            <image src="upload.gif地址" mode="widthFix"></image>
        </view>
        <view class="text">上传中...</view>
        </view>
    </van-popup>
    <van-toast id="van-toast" />
    <van-dialog id="van-dialog" />
</view>
//index.js


import Toast from '@vant/weapp/toast/toast'
var amapFile = require('~/lib/amap/amap-wx.130');
const app = getApp()

Page({
    data: {
      showCamera:false,//相机启动权限
      loading:false,//相机启动加载
      img: '',//拍照定格图片
      infoShow:true,//拍照提示文案展示
      toastShow: false,//上传中展示
      params: {
        gps: {
          lat: '',
          lon: ''
        },
        address: ''
      },
      isSubmitting:false,
      imgList: app.globalData.currentImgList,//已上传照片列表
    },
    //上传照片
    upload() {
      return new Promise((resolve, reject) => {
        console.log(this.data.img)
        wx.uploadFile({
          filePath: this.data.img,
          url: app.baseUrl + '/file/upload/one',
          name: 'file',
          header: {
            "Content-Type": "multipart/form-data" //记得设置
          },
          success({
            data
          }) {
            console.log(JSON.parse(data))
            resolve(JSON.parse(data))
          },
          fail(res) {
            reject(res)
          }
        })
      })
    },
    async handleOk() {
      this.setData({
        toastShow: true
      })
      const res = await this.upload()
      console.log('上传的返回值',res)
      if (!res.success) {
        Toast({
          message: '上传失败,请重试',
          context: this,
          duration: 1000
        })
        this.setData({
          toastShow: false
        })
        return
      }
      let imgList = this.data.imgList
      console.log('初始文件列表',imgList)
      imgList.push({
        fileId:res.data.id,
        fileName:res.data.name,
        fullUrl:res.data.fullUrl,
        suffix:res.data.suffix
      })
      app.globalData.currentImgList=imgList
      this.setData({
        toastShow: false,
        img: '',
        imgList
      })
    },
    //拍照
    takePhoto() {
      if(app.globalData.currentImgList.length >= app.globalData.ableUploadCount){
        return app.toast('拍摄图片已达上限')
      }
      const ctx = wx.createCameraContext()
      ctx.takePhoto({
        quality: 'high',
        success: (res) => {
          console.log('拍照',res)
          this.setData({
            img: res.tempImagePath,
          })
          this.handleOk()
        }
      })
    },
    //图片预览
    picturePreview(){
      wx.navigateTo({ url: `/pages/picturePreview/index` })
    },
    //初始化所需信息
    initShow() {
      this.getPower()
      this.getLocation()
    },
    //判断用户是否开启相机权限
    getPower(){
      const _this = this
      wx.authorize({
        scope:'scope.camera',
        success(){
          _this.setData({
            showCamera:true,
            loading:true
          })
        },
        fail(){
          _this.setData({
            showCamera:false,
            loading:true
          })
        }
      })
    },
      //获取具体位置
    getLocation() {
      const _this = this
      const AmapSdk = new amapFile.AMapWX({key:'填写key值'});
      AmapSdk.getRegeo({
        success: function(data) {
          console.log('amap', data);
          _this.setData({
            'params.gps.lat': data[0].latitude,
            'params.gps.lon': data[0].longitude,
            'params.address': data[0].regeocodeData.formatted_address
          })
        },
        fail: function(res) {
        }
      })

    },
    //拍照提示文案展示
    setInt(){
      setTimeout(() => {
        this.setData({
          infoShow:false
        })
      },2000)
    },
    //提交
    submit(){
      var pages = getCurrentPages();
      var prevPage = pages[pages.length - 2]; //上一个页面
        //直接调用上一个页面的setData()方法,把数据存到上一个页面中去
      prevPage.setData({
            isSubmit: true
          })
          wx.navigateBack({//返回
            delta: 1
          })
    },
    onLoad(options){
      this.setData({
        imgList:app.globalData.currentImgList
      })
      this.initShow()
      this.setInt()
    },
  })

/pages/picturePreview

图片预览页

<!--index.wxml-->

<view class="photo-list" wx:if="{{imgList.length}}">
    <view class="img-box" wx:for="{{imgList}}" wx:key="index" bind:tap="preview" mark:file="{{item}}" mark:index="{{index}}">
        <image src="{{item.fullUrl}}" class="imgs" mode="aspectFill" />
        <image src="/assets/images/delete-icon.png" alt="" class="delete-icon" catchtap="removeImg" data-index="{{index}}" />
    </view>
</view>
<view wx:else class="no-img-box">
    <image class="no-img" src="/assets/images/record/no-img.png"></image>
    <text class="no-img-desc">没有上传图片</text>
</view>
<!-- 图片预览 -->
<view class="picture-preview-box" wx:if="{{isPreview}}" catchtap="closePreview">
    <swiper bind:change="swiperChange" class="swiper" autoplay="{{false}}" current="{{previewImgIndex}}">
        <swiper-item wx:for="{{imgList}}" wx:key="index" class="swiper-item">
            <movable-area scale-area style="width: 750rpx; height: 100vh;">
                <movable-view id="move-img" direction="all" y="{{0}}" x="{{0}}" out-of-bounds scale scale-min="0.5" scale-max="10" scale-value="1" style="width: 750rpx; height: 100vh;">
                    <image src="{{item.fullUrl}}" class="preview-img" />
                </movable-view>
            </movable-area>
        </swiper-item>
    </swiper>
    <view class="remove-btn" catchtap="removeImg">
        <view class="iconfont icon-shenqingshanchu"></view>
        <text class="remove-text">删除</text>
    </view>
</view>
<!-- 删除图片二次确认 -->
<van-dialog title="提示" show="{{ showConfirm }}" show-cancel-button="{{false}}" show-confirm-button="{{false}}" use-slot>
    <view class="modal-view">
        <view class="modal-content">
            <view>是否删除当前图片?</view>
        </view>
        <view class="modal-btn">
            <view class="modal-btn-item modal-btn-close" bindtap="onClose">取消</view>
            <view class="modal-btn-item modal-btn-confirm" bindtap="onConfirm">确定删除</view>
        </view>
    </view>
</van-dialog>
//index.js


const app = getApp()
Page({
    data: {
        imgList: app.globalData.currentImgList, //已拍图片列表
        showConfirm: false, //是否显示二次确认弹窗
        deleteImgIndex: null, //删除图片的索引
        isPreview:false,//预览图片状态
        previewImgIndex:null,//预览图片索引
    },
    //删除图片
    removeImg(e) {
        console.log('删除的图片的索引', e.currentTarget.dataset.index)
        let deleteImgIndex=e.currentTarget.dataset?.index ||this.data.previewImgIndex
        this.setData({
            showConfirm: true,
            deleteImgIndex
        })
    },
    //二次确认弹窗-确认
    onConfirm() {
        let imgList = this.data.imgList
        imgList.splice(this.data.deleteImgIndex, 1)
        this.setData({
            imgList,
            showConfirm: false
        })
        app.globalData.currentImgList = imgList
        if(!imgList.length){
            this.setData({
                isPreview:false,
                previewImgIndex:null
            })
            let title ='图片预览'
            wx.setNavigationBarTitle({
                title
            })
            return
        }
        if(this.data.deleteImgIndex !==0 ){
            this.setData({
                previewImgIndex:this.data.deleteImgIndex-1
            })
        }
        this.updateTitle()
    },
    //二次确认弹窗-取消
    onClose() {
        this.setData({
            showConfirm: false
        })
    },
    //预览图片
    preview(e) {
        console.log('点击预览的图片索引',e.mark.index)
        this.setData({
            isPreview:true,
            previewImgIndex:e.mark.index
        })
        this.updateTitle()
    },
    //预览滑动图片触发事件
    swiperChange(e){
        console.log('滑动监听',e.detail.current)
        this.setData({
            previewImgIndex:e.detail.current
        })
        this.updateTitle()
    },
    //关闭预览
    closePreview(){
        this.setData({
            isPreview:false
        })
        let title ='图片预览'
        wx.setNavigationBarTitle({
            title
        })
    },
    // 更新标题
    updateTitle(){
        let title =`${this.data.previewImgIndex+1}/${app.globalData.currentImgList.length}`
        wx.setNavigationBarTitle({
            title
        })
    },
    onLoad(options) {
        this.setData({
            imgList:app.globalData.currentImgList
        })
    },
    onUnload() {
        wx.redirectTo({
            url: `/pages/takePhoto/index`,
        })
    }
})

 app.js

App({
  globalData: {
    ableUploadCount:null,//附件上传数量限制
    currentImgList:[],//已拍照上传的图片列表
  }
})

  • 10
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值