微信小程序使用webview实现文件上传功能

微信小程序使用webview实现文件上传功能(uni-app)

项目开发了一个批示单的功能,用户填写批示单信息要上传正文及附件(多文件上传,有需要可在文章末尾查看),上传文件功能原调用的是uni.chooseMessageFile方法选择聊天记录中文件。

问题:用户在电脑端打开小程序后发现选择文件按钮点击无反应。
百度后发现此方法电脑端无法使用,并且微信平台暂时没有具体方法,有网上小伙伴说用webview结合input实现。

具体实现:
原设计:A页面选择添加文件后提交
修改后:添加一个B页面(upload文件),在B页面引入webview
A页面跳转到 ===> B页面 接入webview ===> webview(html)使用input选择文件 文件获取后postMessage并返回,具体代码如下

B页面(uploadFile.vue)

<template>
	<view>
	    <!-- 测试完成后改为线上地址 -->
		<web-view src="http://127.0.0.1:5500/%E4%B8%8A%E4%BC%A0%E6%96%87%E4%BB%B6/uploadFile.html"
			@message="handleMessage"></web-view>
	</view>
</template>
<script>
	export default {
		methods: {
			handleMessage(e) {
				console.log('接收到的消息:' + JSON.parse(e.detail.data));
				uni.setStorageSync('fileMsg', JSON.parse(e.detail.data))
			}
		}
	}
</script>

uploadFile.html

创建一个文件夹用来存放webview资源(uploadFile.html是在小程序中接入,本地测试时用vscode打开文件,使用live Serve创建一个本地服务,将服务地址复制放在B页面webview的src中)
在这里插入图片描述

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>上传文件</title>
    <style>
        .uploadFilePage {
            display: flex;
            flex-direction: column;
            align-items: center;
        }

        .inputBox {
            width: 320px;
            height: 220px;
            color: #228EFF;
            font-size: 18px;
            margin-top: 100px;
            border: 1px dashed #228EFF;
            border-radius: 8px;
            display: flex;
            flex-direction: column;
            align-items: center;
            justify-content: center;
        }

        .inputBox img {
            width: 130px;
            height: 130px;
            margin-bottom: 15px;
        }

        .inputBox .tips {
            font-size: 12px;
            color: #666;
            line-height: 30px;
        }


        .fileInput {
            display: none;
        }

        .fileList {
            line-height: 35px;
            margin-top: 20px;
        }

        .fileList .fileOne {
            display: flex;
            align-items: center;
        }

        .fileList .deleteIconBox {
            width: 50px;
            height: 35px;
            display: flex;
            align-items: center;
            justify-content: center;
        }

        .fileList .deleteIconBox img {
            width: 26px;
            height: 26px;
        }

        .goBackBtn {
            width: 120px;
            height: 45px;
            line-height: 45px;
            text-align: center;
            background-color: #228EFF;
            border-radius: 6px;
            color: #fff;
            margin-top: 35px;
        }

        .alert {
            position: fixed;
            top: 40%;
            left: 50%;
            transform: translate(-50%, -50%);
            padding: 10px;
            background-color: #faa734;
            color: #fff;
            border-radius: 6px;
        }
    </style>
    <!-- 微信 JS-SDK 如果不需要兼容小程序,则无需引用此 JS 文件。 -->
    <script type="text/javascript" src="//res.wx.qq.com/open/js/jweixin-1.4.0.js"></script>
    <!-- uni 的 SDK,必须引用。 -->
    <script type="text/javascript" src="//js.cdn.aliyun.dcloud.net.cn/dev/uni-app/uni.webview.0.1.52.js"></script>
    <script src="./vue.min.js"></script>
</head>

<body>
    <div class="uploadFilePage" id="app">
        <div class="inputBox" @click="makeFileInputClick">
            <img src="./image/uploadIcon.png" alt="">
            <div class="text">点击上传</div>
            <div class="tips">* 文件大小限制为10MB</div>
            <input type="file" class="fileInput" name="222" @change="chooseFile" ref="fileInput">
        </div>
        <div class="fileList">
            <div v-for="(item, index) in filesList.basicData" :key="index" class="fileOne">{{item.name}} 上传成功 <div
                    class="deleteIconBox" @click="deleteFile(index)"><img src="./image/deleteIcon.png" alt="">
                </div>
            </div>
        </div>
        <div @click="goBack" class="goBackBtn">完成</div>
        <div class="alert" v-show="isShowAlert">文件大小超过限制,请重新上传</div>
    </div>

    <script>
        console.log(Vue);
        new Vue({
            el: '#app',
            data: {
                filesList: {
                    basicData: [],  // 原始数据
                    handledData: []  // 转化为base64的数据
                },
                isShowAlert: false
            },
            methods: {
                makeFileInputClick() {
                    this.$refs.fileInput.click()
                },
                // 文件转base64
                fileToBase64(file) {
                    return new Promise(function (resolve, reject) {
                        var reader = new FileReader();
                        reader.readAsDataURL(file);
                        reader.onload = function () {
                            typeof reader.result === 'string' && resolve(reader.result) || reject();
                        };
                        reader.onerror = function (error) { return reject(error); };
                    });
                },
                async chooseFile(e) {
                    let fileList = this.$refs.fileInput.files
                    for (const item of fileList) {
                    	// 限制文件大小
                        if (item.size / 1024 / 1024 > 10) {
                            this.isShowAlert = true;
                            setTimeout(() => {
                                this.isShowAlert = false;
                            }, 2500)
                            return
                        }
                        this.filesList.basicData.push(item);
                        this.filesList.handledData.push({ name: item.name, file: await this.fileToBase64(item) });
                    }

                },
                deleteFile(index) {
                    this.filesList.basicData.splice(index, 1)
                    this.filesList.handledData.splice(index, 1)
                },
                goBack() {
                    uni.postMessage({
                        data: JSON.stringify(this.filesList.handledData)
                    });
                    uni.navigateBack()
                }
            }
        })
    </script>
</body>

</html>

在这里插入图片描述

A页面

onShow() {
	if (!uni.getStorageSync('fileMsg')) return
	let fileMsg = uni.getStorageSync('fileMsg');
	uni.removeStorageSync('fileMsg');
	fileMsg.forEach(item => {
		item.file = item.file.split('base64,')[1]  // 不加此句是报了下图的错误,百度后是由于base64,及之前的原因,删除之后就不报错了
		this.base64ToTempFilePath(item.name, item.file, (tempFilePath) => {
			console.log('转换成功,临时地址为:', tempFilePath)
			// 自己的业务逻辑...
		}, function() {
			uni.showToast({
				title: '文件转换失败,请重试',
				icon: 'none'
			})
		})
	})
},
methods:{
	base64ToTempFilePath(fileName, base64Data, success, fail) {
		const fs = uni.getFileSystemManager()
		// const fileName = 'temp_image_' + Date.now() + '.png' // 自定义文件名,可根据需要修改
		const filePath = uni.env.USER_DATA_PATH + '/' + fileName
		const buffer = uni.base64ToArrayBuffer(base64Data)
		fs.writeFile({
			filePath,
			data: buffer,
			encoding: 'binary',
			success() {
				success && success(filePath)
			},
			fail() {
				fail && fail()
			}
		})
	},
}

转换为base64时报错,删除base64 中开头的 data:xxx/xxx;base64, 即可
将base64格式图片转化为临时路径时报错
测试完成后,将html页面及相关文件上传至服务器,并在微信开放平台中进行配置 开发==>开发管理==>业务域名
配置webview业务域名

多文件上传

微信小程序实现多文件同时上传

本文基于以下文章所写:

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值