【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>
相关推荐
Martin -Tang44 分钟前
vite和webpack的区别
前端·webpack·node.js·vite
迷途小码农零零发1 小时前
解锁微前端的优秀库
前端
王解2 小时前
webpack loader全解析,从入门到精通(10)
前端·webpack·node.js
老码沉思录2 小时前
写给初学者的React Native 全栈开发实战班
javascript·react native·react.js
我不当帕鲁谁当帕鲁2 小时前
arcgis for js实现FeatureLayer图层弹窗展示所有field字段
前端·javascript·arcgis
那一抹阳光多灿烂2 小时前
工程化实战内功修炼测试题
前端·javascript
放逐者-保持本心,方可放逐3 小时前
微信小程序=》基础=》常见问题=》性能总结
前端·微信小程序·小程序·前端框架
毋若成5 小时前
前端三大组件之CSS,三大选择器,游戏网页仿写
前端·css
红中马喽5 小时前
JS学习日记(webAPI—DOM)
开发语言·前端·javascript·笔记·vscode·学习
Black蜡笔小新6 小时前
网页直播/点播播放器EasyPlayer.js播放器OffscreenCanvas这个特性是否需要特殊的环境和硬件支持
前端·javascript·html