需求:
1.当未拍摄任何照片或者预览相册中无照片时,不展示预览相册icon入口及提交按钮
2.图片预览页支持列表中点击删除icon删除,图片点击时全屏预览,预览中支持放大缩小、左右滑动切换列表中的图片,删除当前预览图片
3.列表中删除图片或预览时删除图片均需二次确认
4.点击图片预览时,导航栏显示当前预览图片索引/全部图片数量
预览组件实现方法:
组合微信小程序movable-area、movable-view、swiper-item组件
/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:[],//已拍照上传的图片列表
}
})