当前位置:   article > 正文

【vue/uniapp】使用 uni.chooseImage 和 uni.uploadFile 实现图片上传(包含样式,可以解决手机上无法上传的问题)_uni图片上传

uni图片上传

引入:
之前写过一篇关于 uview 1.x 版本上传照片 的文章,但是发现如果是在微信小程序的项目中嵌入 h5 的模块,这个 h5 的项目使用 u-upload 的话,图片上传功能在电脑上正常,但是在手机的小程序上测试就不会生效,点击上传加号按钮毫无反应。
解决方法:
现在最终的解决方法是,使用 uniapp 的 uni.chooseImage 来选择照片,使用 uni.uploadFile 来上传图片,其他所有的样式和逻辑都自己来实现,最终的效果长这样:

代码与解析:
单独写一个组件,先实现样式:

<template>
    <view class="meeting-image">
        <view class="title">
            <text></text>
            <!-- 展示图片张数 -->
            <text style="color: #a1a1a1;">({{ list.length }}/9)</text>
        </view>
        <view class="img_wrap flex-row flex-justify-between">
            <view class="img_box" v-for="(item, index) in list" :key="index">
                <!-- 展示上传之后的图片 -->
                <image :src="item.imgUrl" class="pic" mode="aspectFill" @click="previewImage(index)" />
                <!-- 删除图标 -->
                <!-- 这里的删除图标叉叉是用的在线网址,$public 是挂载在原型上的,可以自定义 -->
                <image 
                    :src="`${$public()}/project-meeting/icon_20_close.png`" 
                    class="close"
                    @click.stop="handleDeleteImg(index, item)" />
            </view>
            <!-- 上传的方框 -->
            <view 
                class="upload-box" 
                @click="chooseImg" 
                v-if="list.length !== 9 && isSponsorUserFlag == 1"
            ></view>
        </view>
        <u-toast ref="uToast" />
    </view>
</template>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
.meeting-image {
    .title {
        font-size: 32rpx;
        line-height: 40 rpx;

        text:nth-of-type(1) {
            color: #ff3f30;
            padding-right: 4rpx;
        }

        text:nth-of-type(3) {
            padding-left: 12rpx;
            color: #cccccc;
        }
    }

    .img_wrap {
        flex-wrap: wrap;

        &::after {
            width: calc((100% - 40rpx) / 3);
            display: block;
            content: '';
        }

        .img_box {
            margin-top: 20rpx;
            position: relative;
            width: calc((100% - 40rpx) / 3);
            height: 220rpx;

            .pic {
                width: 100%;
                height: 100%;
                object-fit: cover;
                border-radius: 14rpx;
            }

            .close {
                position: absolute;
                top: -8rpx;
                right: -8rpx;
                width: 40rpx;
                height: 40rpx;
            }
        }

        .upload-box {
            position: relative;
            width: calc((100% - 40rpx) / 3);
            height: 220rpx;
            border: 1px solid #e5e5e5;
            box-sizing: border-box;
            position: relative;
            border-radius: 14rpx;
            margin-top: 20rpx;

            &::after {
                display: block;
                content: '';
                width: 1px;
                height: 96rpx;
                background-color: #e5e5e5;
                position: absolute;
                left: 105rpx;
                top: 50rpx;
            }

            &::before {
                display: block;
                content: '';
                width: 96rpx;
                height: 1px;
                background-color: #e5e5e5;
                position: absolute;
                right: 60rpx;
                top: 100rpx;
            }
        }
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81

js 逻辑部分,我这里后端提供的 api 有上传(查询文件地址),即代码中的 previewUrl ,删除的实现方法是在本地进行的,是对数组进行 splice 之后,再将最新的图片数组保存进大数组一次,最后再进行上传,注释写的很详细,方便以后回顾查看。

简单解释:

chooseImg 是最先执行的函数,即点击上传按钮时执行,进来判断是不是数量超过了 9 张,没超过就往下走;
使用 uni.chooseImage 进行图片选择功能,配置相应参数和值,选择成功,走到 then 的成功回调里,回显照片,此时调接口 previewUrl 来上传获取图片id;
然后将图片保存进数组中

<script>
import { BASE_URL } from '@/pages/workTable/utils/constant'
import { previewUrl } from '@/pages/workTable/utils/api.js'

export default {
    name: 'meeting-image',
    // 接收参数
    props: {
        fileList: {
            type: Array,
            default: []
        },
        // 用于该页面有很多项,而每一项都需要传一组图片的页面
        subItem: {

        },
        // 用于只传一组图片的页面
        picListArr: {

        },
        picList: {

        }
    },
    data() {
        return {
            list: [],
            count: 9,
        }
    },

    computed: {},
    methods: {
        // 预览功能暂时有问题
        previewImage(index) {
            console.log('预览', this.list.map(el => el.imgUrl));
            uni.previewImage({
                current: index,
                urls: this.list.map(el => el.imgUrl)
            })
        },
        // 点击上传按钮触发
        chooseImg() {
            // 如果大于 9 张就不触发底下的 uni.chooseImage
            if (this.count == 0) {
                this.$refs.uToast.show({
                    title: '最多能上传9张照片',
                    duration: 2000
                })
                return
            }
            uni.chooseImage({
                // 最多可以选择的图片张数,默认9
                count: this.count,
                // original 原图,compressed 压缩图,默认二者都有
                sizeType: ['original', 'compressed'],
                // album 从相册选图,camera 使用相机,默认二者都有
                sourceType: ['album', 'camera'],
                success: res => {
                    // console.log('res',res);
                    uni.showLoading({
                        title: '上传中'
                    })
                    Promise.all(
                        res.tempFilePaths.map(item => {
                            return this.uploadFile({
                                filePath: item
                            })
                        })
                    )
                        .then(re => {
                            uni.hideLoading()
                            // let fileList = []
                            re.map((el, index) => {
                                let data = JSON.parse(el.data)
                                // 用于上传成功后照片回显
                                // console.log('data',data.data);
                                previewUrl(data.data).then(res => {
                                    console.log('我要预览图片', res); this.list.push({ fileUrl: data.data, imgUrl: res.data })
                                    setTimeout(() => {
                                        console.log('this.list', this.list);
                                        this.saveFile(this.list)
                                    }, 800)
                                })
                            })
                        })
                        .catch(err => {
                            console.log('err', err);
                            this.$refs.uToast.show({
                                title: '上传失败',
                                duration: 2000
                            })
                            uni.hideLoading()
                        })
                },
                fail: () => { }
            })
        },
        // 上传图片
        uploadFile({ filePath }) {
            return new Promise((resolve, reject) => {
                uni.uploadFile({
                    url: `${BASE_URL}/mobilemanage/api/common/upload?typeEnum=IMAGE`,
                    filePath: filePath,
                    name: 'file',
                    header: {
                        'site3-f-ue': uni.getStorageSync('site3-f-ue')
                    },
                    formData: {
                        typeEnum: "IMAGE",
                    },
                    success: res => {
                        console.log('调用上传接口的结果', res);
                        resolve(res)
                    },
                    fail: error => {
                        reject(error)
                    }
                })
            })
        },
        // 将图片保存进数组
        saveFile(list) {
            console.log('aaaaaaaaaa', list);
            // 子组件拿接到的父组件传过来的值,subItem 是每一项的数据,里面有 picList 和 picListArr
            console.log('父组件传过来的subItem', this.subItem);
            // 每一项都需要上传照片这种情况才需要用到 subItem
            if (this.subItem) {
                console.log('有 subItem 的情况');
                let subItem = this.subItem
                subItem.picList = []
                subItem.picListArr = []

                list.map(async item => {
                    console.log('bbbbbbbb', item);
                    subItem.picList.push({
                        fileUrl: item.fileUrl
                    })
                    console.log('subItem.picList', subItem.picList);
                })
                console.log('subItem.picList', subItem.picList);
                subItem.picList.map(item => {
                    subItem.picListArr.push(item.fileUrl)
                })
                console.log('subItem.picListArr', subItem.picListArr);
            } else {
                console.log('没有subItem的情况', list);
                // 只需要上传一组图片
                let picList = this.picList
                let picListArr = this.picListArr

                picList = []
                picListArr = []
                // console.log('list',list);
                list.map(async item => {
                    console.log('qqqqqqqqqqqq', item);
                    picList.push({
                        fileUrl: item.fileUrl
                    })
                })
                this.$emit('getPicList', picList)
                console.log('照片列表', picList);
            }
        },
        // 删除图片
        handleDeleteImg(index, item) {
            this.list.splice(index, 1)
            this.saveFile(this.list)
            this.$refs.uToast.show({
                title: '删除成功',
                duration: 2000
            })
        }
    },
    watch: {
        // 监视当前图片数组长度,增减张数显示
        fileList: {
            handler: function (value) {
                this.list = value
                this.count = 9 - this.list.length
            },
            deep: true,
            immediate: true
        }
    }
}
</script>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120
  • 121
  • 122
  • 123
  • 124
  • 125
  • 126
  • 127
  • 128
  • 129
  • 130
  • 131
  • 132
  • 133
  • 134
  • 135
  • 136
  • 137
  • 138
  • 139
  • 140
  • 141
  • 142
  • 143
  • 144
  • 145
  • 146
  • 147
  • 148
  • 149
  • 150
  • 151
  • 152
  • 153
  • 154
  • 155
  • 156
  • 157
  • 158
  • 159
  • 160
  • 161
  • 162
  • 163
  • 164
  • 165
  • 166
  • 167
  • 168
  • 169
  • 170
  • 171
  • 172
  • 173
  • 174
  • 175
  • 176
  • 177
  • 178
  • 179
  • 180
  • 181
  • 182
  • 183
  • 184
  • 185
  • 186
  • 187

使用的时候,父组件进行调用传值:

import uploadImage from '../components/upload-image'
  • 1
components: {
    uploadImage
},
  • 1
  • 2
  • 3
<upload-image 
    :fileList="subItem.picList" 
    :subItem="subItem" 
    :projectMeetingId="1"
    :isSponsorUserFlag="1"
></upload-image>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
本文内容由网友自发贡献,转载请注明出处:https://www.wpsshop.cn/w/2023面试高手/article/detail/190284
推荐阅读
相关标签
  

闽ICP备14008679号