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

引入:

之前写过一篇关于 uview 1.x 版本上传照片 的文章,但是发现如果是在微信小程序的项目中嵌入 h5 的模块,这个 h5 的项目使用 u-upload 的话,图片上传功能在电脑上正常,但是在手机的小程序上测试就不会生效,点击上传加号按钮毫无反应。
解决方法:

现在最终的解决方法是,使用 uniapp 的 uni.chooseImage 来选择照片,使用 uni.uploadFile 来上传图片,其他所有的样式和逻辑都自己来实现,最终的效果长这样:

代码与解析:

单独写一个组件,先实现样式:

html 复制代码
<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>
css 复制代码
.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;
            }
        }
    }
}

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

简单解释:

chooseImg 是最先执行的函数,即点击上传按钮时执行,进来判断是不是数量超过了 9 张,没超过就往下走;

使用 uni.chooseImage 进行图片选择功能,配置相应参数和值,选择成功,走到 then 的成功回调里,回显照片,此时调接口 previewUrl 来上传获取图片id;

然后将图片保存进数组中

javascript 复制代码
<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>

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

javascript 复制代码
import uploadImage from '../components/upload-image'
javascript 复制代码
components: {
    uploadImage
},
html 复制代码
<upload-image 
    :fileList="subItem.picList" 
    :subItem="subItem" 
    :projectMeetingId="1"
    :isSponsorUserFlag="1"
></upload-image>
相关推荐
前端小小王29 分钟前
React Hooks
前端·javascript·react.js
迷途小码农零零发38 分钟前
react中使用ResizeObserver来观察元素的size变化
前端·javascript·react.js
娃哈哈哈哈呀1 小时前
vue中的css深度选择器v-deep 配合!important
前端·css·vue.js
旭东怪1 小时前
EasyPoi 使用$fe:模板语法生成Word动态行
java·前端·word
ekskef_sef3 小时前
32岁前端干了8年,是继续做前端开发,还是转其它工作
前端
sunshine6413 小时前
【CSS】实现tag选中对钩样式
前端·css·css3
真滴book理喻4 小时前
Vue(四)
前端·javascript·vue.js
蜜獾云4 小时前
npm淘宝镜像
前端·npm·node.js
dz88i84 小时前
修改npm镜像源
前端·npm·node.js
Jiaberrr4 小时前
解锁 GitBook 的奥秘:从入门到精通之旅
前端·gitbook