uniapp写h5如何封装一个图片上传预览并且有进度条的组件

开发背景:

首先项目是用uniapp写的h5项目,要求能上传、预览、和进度条展示,还要求总览的时候用缩略图,点开预览要原图,(不得不吐槽一下)
开发环境:
uniapp +阿里云存储

先看截图效果:
在这里插入图片描述
好了直接上代码

// photo-picker.vue
<template> 
    <view class="imgs">
        <view class="image" v-for="(item, index) in localPhotos" :key="index">
            <image class="img" :src="item.path" mode="aspectFill" @click="previewImage(index)"></image> 
            <view class="del" mode="widthFix" @click="delImg(index)">
                <uni-icons color='white' custom-prefix="custom-icon" type="closeempty" size="16"></uni-icons>
            </view>
            
            <view class="file-picker__progress" v-if="(item.progress && item.progress !== 100) || item.progress === 0"> 
                <progress class="file-picker__progress-item" :activeColor="'#FF7300'" :percent="item.progress === -1?0:item.progress" stroke-width="12" :backgroundColor="item.errMsg?'#ff5a5f':'#EBEBEB'"/>
            </view>
        </view>
        <!-- 实例用的插槽 -->
        <slot name="instance" v-if="localPhotos.length===0"></slot>
        <view class="icon_box"  @click="uploadImg()" v-show="isShow && photos.length < astrict">
            <image class="icon-add" src="/static/images/img_photo_1.png"></image>
            <view class="icon-title">上传图片</view> 
        </view>
    </view> 
</template>

<script>
import api from '@/static/api.js';
import { recursionCompressH5 } from '@/static/util.js';
export default {
    props:{
        //原图
        photos:{
            type: [Array,String],
            default: () => [],
            // required: true // 必填 
        },
        //缩略图
        thumbnailPhotos:{
            type: [Array],
            default: () => [],
            required: true // 必填 
        },
        //限制传多少张
        astrict:{
            type: Number,
            default: 1
        }
    },
    data() {
        return {
            localPhotos: [],//保存本地图片
            isShow:true
        }
    },
    methods: {
        //预览图片
        previewImage(current = 0) {
            uni.previewImage({
                current,
                urls: this.photos,
                loop: true,
				indicator: "default",
                longPressActions: {
                    itemList: ['发送给朋友', '保存图片', '收藏'],
                    success: function (data) {
                    },
                    fail: function (err) {
                    }
                }
            })
        },
        //执行回调
        callback(file,i){
            uni.uploadFile({
                url: api.upLoadImg,
                filePath: file.path,
                name: 'file_img',
                success: (uploadFileRes) => {
                    let data = JSON.parse(uploadFileRes.data);

                    this.photos[i]=data.data.url;//图片链接放到原图数组里

                    this.thumbnailPhotos[i] = { path:data.data.thumbnail, progress: 100 }
                    // this.$emit("onSaveThumbnail",this.thumbnailPhotos)//图片链接放到缩略图数组里

                    this.localPhotos[i].progress = 100 
                    this.localPhotos[i].errMsg = false
                    this.$set(this.localPhotos,i,this.localPhotos[i])//本地图片放到存放本地图片的数组里
                    
                    if (++this.num === this.len) {
                        this.isShow = true
                        uni.hideLoading()
                        this.num = 0
                        this.len = 0
                    }
                },
                fail:(err) => {
                    this.localPhotos[i].errMsg = true
                    this.localPhotos[i].progress = -1
                    this.$set(this.localPhotos,i,this.localPhotos[i])//本地图片放到存放本地图片的数组里
                    if (++this.num === this.len) {
                        this.isShow = true
                        uni.hideLoading()
                        this.num = 0
                        this.len = 0
                    }
                }
            })
        },
        //进度条自动前进
        autoStep(v,i){
            let timer  = null
            timer = setInterval(() => { 
                if (v.progress >= 90) {
                    clearInterval(timer);
                }else if(v.progress === -1){
                    clearInterval(timer);
                }else{
                    v.progress += 5
                    this.$set(this.localPhotos,i,v) 
                }
            }, 500);
        },
        //获取图片
        uploadImg() {
            let sun = this.astrict - this.photos.length;
            uni.chooseImage({
                count: sun,
                sizeType: ['compressed'],
                success: (res) => {
                    this.isShow = false
                    uni.showLoading({
                        title: '上传中...',
                        mask:true
                    })
                    this.len =res.tempFilePaths.length
                    this.num = 0
                    res.tempFiles.forEach((v, i) => {
                        v.progress = 0
                        this.localPhotos.push(v)
                    })

                    //走模拟进度条
                    this.localPhotos.forEach((item,index)=>{ 
                        if (item.progress === 0) {
                            //调用模拟进度条
                            this.autoStep(item, index)
                             //调用压缩方法 
                            recursionCompressH5(item,index,this.callback,2) 
                        }
                    })
                },
                fail: (err) => {
                }
            });
        },
        //删除图片
        delImg(index) {
            this.photos.splice(index, 1)
            this.localPhotos.splice(index, 1)
            this.thumbnailPhotos.splice(index, 1)
        },
    },
    watch: {
        thumbnailPhotos() {
            this.localPhotos = JSON.parse(JSON.stringify(this.thumbnailPhotos))
        }
    }, 
}
</script>

<style lang="scss" scoped>
.imgs{
    margin-top:10upx;
    width: 100%;
    display: flex;
    align-items: center;
    flex-wrap: wrap;
    
    .image{
        width: 202upx;
        height: 202upx;
        border-radius: 16upx;
        overflow: hidden;
        margin: 0 10upx 10upx 0;
        position: relative;
        
        .img{
            width: 100%;
            height: 100%;
            display: block;
        }
        
        .del{
            background-color: #000;
            opacity: 0.5;
            width: 44upx;
            height: 44upx;
            border-radius: 50%;
            position: absolute;
            top: 4upx;
            right: 4upx;
            text-align: center; 
        }
        .file-picker__progress {
            position: absolute;
            bottom: 0;
            left: 0;
            right: 0;
            /* border: 1px red solid; */
            z-index: 99;
        }
    
        .file-picker__progress-item {
            width: 100%; 
        }
    }
    .icon_box{ 
        width: 202upx;
        height: 202upx; 
        border-radius: 16upx;
        background-color:#F4F4F4;
        text-align: center;
        // margin-top: -10upx;
        .icon-add {
            width: 80upx;
            height: 80upx;  
            margin: 40upx 0 5upx;
        }

        .icon-title { 
            font-size: 24upx;
            font-family: 10pxPingFangSC-Regular, PingFang SC;
            font-weight: 400;
            color: #999999;
        }
    }
}
</style>

如何使用呢?

<upload-file class="img_picker" :astrict="9" :photos.sync="formInfo.medical_treatment_photos" :thumbnailPhotos.sync="formInfo.thumbnail_medical_treatment_photos"/>
//photo是原图的数组   如:["http://draftimg.zhongaihuzhu.com/uploads/20220914/6VaNfQGheXlgsWyyoSLWhxWZoUp6Je4jpS5IS0og.jpg","http://draftimg.zhongaihuzhu.com/uploads/20220914/6VaNfQGheXlgsWyyoSLWhxWZoUp6Je4jpS5IS0og.jpg"]
//thumbnailPhotos是缩略图的数组  
//astrict是上传图片张数,不传默认一张
//此处使用.sync传参可实现子组件修改父组件的数据,

thumbnailPhotos 缩略图的数组,要特别提醒一下,由于要有进度条效果,所以,该数组格式为

[
    {
    path:"http://draftimg.zhongaihuzhu.com/uploads/20220914/6VaNfQGheXlgsWyyoSLWhxWZoUp6Je4jpS5IS0og.jpg",
    progress:0
    }
   ]
  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值