问题
在微信小程序开发开发中,可能会遇到需要上传文件的场景,用户需要从手机文件管理器中选择文件,然后上传到服务器.但是微信小程序只支持选择回话中的文件,无法从手机中选择
方案
我们可以通过小程序的web-view实现.通过html的实现文件上传.
代码
这个代码是基于微信小程序的,当前集成在一个组件中。上传一个文件就会返回到组件中。
web-view页面
<template>
<web-view
class="web-view"
@message="message"
:src="src"
></web-view>
</template>
<script>
import { HOMEINDEX_NAME, ACCESS_TOKEN, CURRENT_URL } from "@/common/util/constants"
export default {
name: 'JkyJeecgSlpzWxIdentification',
data() {
return {
src: ``,
prevKey: ''
};
},
onl oad(options) {
this.prevKey = JSON.parse(decodeURIComponent(options.query)).prevKey
let baseUrl = this.$config.identificationUrl + '/' + uni.getStorageSync(CURRENT_URL)
let token = uni.getStorageSync(ACCESS_TOKEN)
this.src = this.$config.identificationUrl + `/fileUpload/index.html?baseUrl=` + baseUrl + `&token=` + token
console.log(this.src, 'this.src')
},
created() {
},
beforeMount() {
},
mounted() {
},
methods: {
message(arg) {
console.log(arg, '接收h5页面发来的消息')
let pages = getCurrentPages();
let prev = pages[pages.length - 2]; //上一页
if (this.prevKey) {
if (arg.target.data[0].message == '上传成功') {
prev.$vm[this.prevKey + 'Msg'] = '上传成功'
prev.$vm[this.prevKey] = arg.target.data[0].url
} else if (arg.target.data[0].message == '上传失败') {
prev.$vm[this.prevKey + 'Msg'] = '上传失败'
}
}
},
},
};
</script>
<style lang="less" scoped>
</style>
my-file-upload.vue
<template>
<view>
<l-file
ref="lFile"
:prevKey="prevKey"
:logo="logo"
@up-success="onSuccess"
></l-file>
<button
type="primary"
size="mini"
@click="upload"
v-if="!disabled"
>文件上传</button>
<view>
<view
class="cu-form-group"
v-for="(item,index) in fileList"
:key="index"
:data-url="item"
>
<view
class="text_fileName"
@tap.stop="reviewFile(item)"
>{{item}}</view>
<view
v-if="!disabled"
class="cu-tag"
@tap.stop="DelImg"
:data-index="index"
>
<uni-icons
type="clear"
color="#c0c4cc"
size="24"
></uni-icons>
</view>
</view>
</view>
</view>
</template>
<script>
import { ACCESS_TOKEN, CURRENT_URL } from '@/common/util/constants.js'
export default {
name: 'MyFileUpoad',
props: {
prevKey: { type: String },
disabled: {
type: Boolean,
default: () => {
return false
}
},
value: { type: String },
size: { //文件大小限制
type: Number,
default: () => {
return 100
}
},
extName: { //文件大小限制
type: Array,
default: () => {
return [".docx", ".doc", ".rtf", ".txt", ".xltx", ".xls", ".xlsm", ".xlsb", ".csv", ".xml", ".pptx", ".ppt", ".xps", ".pdf", ".jpg", ".png", ".jpeg", ".odf", ".tiff", ".svg", ".zip", ".rar", ".xlsx"]
}
},
},
mounted: function () {
},
data() {
return {
logo: 'https://gimg2.baidu.com/image_search/src=http%3A%2F%2Fbpic.588ku.com%2Felement_origin_min_pic%2F00%2F00%2F07%2F155788a6d8a5c42.jpg&refer=http%3A%2F%2Fbpic.588ku.com&app=2002&size=f9999,10000&q=a80&n=0&g=0n&fmt=jpeg?sec=1619847627&t=2da40b583002205c204d980b54b35040',
header: '',
fileList: [],
pathlist: [],
uploadUrl: "/sys/common/upload",
downLoadUrl: "/sys/common/static/",
num: 0
}
},
watch: {
value: {
handler(val) {
console.log(val, 79)
if (val && !this.num) {
this.fileList = val.split(',');
this.num++;
}
},
deep: true,
immedaite: true
}
},
created() {
if (this.value) {
this.fileList = this.value.split(',');
}
},
methods: {
reviewFile(item) {
let fileType = item.split('.')[item.split('.').length - 1]
let url = this.$config.apiUrl + uni.getStorageSync(CURRENT_URL) + this.downLoadUrl + item
/* 下载返回临时路径(退出应用失效) */
this.$refs.lFile.download({ url })
.then(path => {
/* 打开附件 */
this.$refs.lFile.open(path, fileType);
});
},
onWebViewSuccess(path) {
if (path) {
this.pathlist.push(path);
this.$emit('file-change', this.pathlist.join(','))
if (this.fileList.length != 0) {
this.fileList = this.fileList.concat([path])
} else {
this.fileList.push(path)
}
} else {
uni.showToast({
title: `上传失败`
})
}
},
onSuccess(res) {
if (res.data.success) {
let path = res.data.message;
this.pathlist.push(path);
this.$emit('file-change', this.pathlist.join(','))
if (this.fileList.length != 0) {
this.fileList = this.fileList.concat([path])
} else {
this.fileList.push(path)
}
} else {
uni.showToast({
title: `上传失败`
})
}
},
// 选择上传触发函数
upload() {
let that = this
this.$refs.lFile.upload({
//替换为你的上传接口地址
url: that.$config.apiUrl + uni.getStorageSync(CURRENT_URL) + that.uploadUrl,
// 服务端接收附件的key
name: 'file',
//根据你接口需求自定义 (优先不传content-type,安卓端无法收到参数再传)
header: {
'X-Access-Token': uni.getStorageSync(ACCESS_TOKEN)
},
// 限制选择附件的大小上限,默认10M
// maxSize: 20,
// 若需要在body单独添加附件名或附件大小如下方式传入组件:
// addName: '后端要的附件名称字段key,此处请勿写name的同值如(file),会覆盖name',
// addSize: '后端要的附件大小字段key'
// body参数直接写key,value,如:
// date: '2020-1-1',
// key2: 'value2',
});
},
DelImg(e) {
uni.showModal({
title: '提示',
content: '确认要删除吗',
cancelText: '取消',
confirmText: '确认',
success: res => {
if (res.confirm) {
this.pathlist.splice(e.currentTarget.dataset.index, 1)
this.fileList.splice(e.currentTarget.dataset.index, 1)
this.$emit('file-change', this.pathlist.join(','))
}
}
})
},
}
}
</script>
<style lang="less" scoped>
.cu-tag {
background: transparent !important;
}
.text_fileName {
width: 85%;
overflow: hidden;
text-overflow: ellipsis;
word-break: break-all;
}
</style>
组件用法
<myFileUpload
ref="sceneFileRef"
prevKey="sceneFile"
:disabled="lookDis"
v-model="model.sceneFile"
@file-change="fileChange('sceneFile',$event)"
/>
fileChange(key, value) {
this.$set(this.model, key, value);
},
l-file.vue
<template>
<view>
<view
class='t-toptips'
:style="{top: top,background: cubgColor}"
:class="[show?'t-top-show':'']"
>
<view
v-if="loading"
class="flex flex-sub"
>
<view class="flex flex-sub">
<view class="cu-progress flex-sub round striped active sm">
<view :style="{ background: color,width: value + '%'}"></view>
</view>
<text class="margin-left">{{value}}%</text>
</view>
<view
@click="downOnAbort"
v-if="value<100"
class="close"
>取消</view>
</view>
<block v-else>{{msg}}</block>
</view>
<!-- #ifdef H5 -->
<h5-file
v-if="showH5"
ref="h5File"
:logo="logo"
:showTip="showTip"
:progress="value"
@abort="onAbort"
@close="onCloseH5"
></h5-file>
<!-- #endif -->
</view>
</template>
<script>
import h5File from './h5-file.vue';
export default {
components: { h5File },
props: {
logo: {
type: String,
default: 'https://gimg2.baidu.com/image_search/src=http%3A%2F%2Fbpic.588ku.com%2Felement_origin_min_pic%2F00%2F00%2F07%2F155788a6d8a5c42.jpg&refer=http%3A%2F%2Fbpic.588ku.com&app=2002&size=f9999,10000&q=a80&n=0&g=0n&fmt=jpeg?sec=1619847627&t=2da40b583002205c204d980b54b35040'
},
prevKey: {
type: String,
default: ''
},
top: {
type: String,
default: 'auto'
},
bgColor: {
type: String,
default: 'rgba(49, 126, 243, 0.5)',
},
color: {
type: String,
default: '#55aa00',
}
},
data() {
this.uploadTask = null;
this.downloadTask = null;
return {
cubgColor: '',
loading: false,
value: 5,
show: false,
msg: '执行完毕~',
showH5: false,
showTip: false,
}
},
methods: {
toast(title = '', { duration = 2000, icon = 'none' } = {}) {
uni.showToast({ title, duration, icon });
},
getRequest(url) {
let theRequest = new Object();
let index = url.indexOf("?");
if (index != -1) {
let str = url.substring(index + 1);
let strs = str.split("&");
for (let i = 0; i < strs.length; i++) {
theRequest[strs[i].split("=")[0]] = unescape(strs[i].split("=")[1]);
}
}
return theRequest;
},
/*
上传说明:
url:上传接口地址
name:上传文件key值
header: 上传接口请求头
...:body内其他参数
*/
appChooseFile({ cuWebview = '', url, name = 'file', header, addName = '', addSize = '', maxSize = 10, ...formData } = {}) {
// #ifdef APP-PLUS
let wvPath = '/uni_modules/l-file/hybrid/html/index.html';
let wv = plus.webview.create("", wvPath, {
'uni-app': 'none',
top: 0,
height: '100%',
background: 'transparent'
}, {
url,
header,
addName,
addSize,
maxSize,
formData,
key: name,
logo: this.logo
});
wv.loadURL(wvPath);
this.$root.$scope.$getAppWebview().append(wv);
wv.overrideUrlLoading({ mode: 'reject' }, (e) => {
let { fileName, size, str } = this.getRequest(e.url);
fileName = unescape(fileName);
str = unescape(str);
return this.handleBack(fileName, str, size);
});
// #endif
},
wxChooseFile() {
this.$Router.push({ path: '/components/my-componets/webView-fileUpload',query:{prevKey:this.prevKey}});
},
wxChooseFile1({ maxSize = 10, ...param }) {
wx.chooseMessageFile({
count: 1,
type: 'file',
success: ({ tempFiles }) => {
this.setdefUI();
let file = tempFiles[0];
if (file.size > (1024 * 1024 * Math.abs(maxSize))) {
uni.showToast({
title: `单个文件请勿超过${maxSize}M,请重新上传`,
icon: 'none'
});
return this.errorHandler('文件选择失败', this.upErr);
}
this.handleWXUpload(param, file);
},
fail: () => this.errorHandler('文件选择失败', this.upErr)
})
},
h5ChooseFile({ maxSize = 10, ...param } = {}) {
this.showH5 = true;
this.value = 0;
this.$nextTick(() => {
this.$refs.h5File.hFile.onchange = (event) => {
let file = event.target.files[0];
if (file.size > (1024 * 1024 * Math.abs(maxSize))) {
uni.showToast({
title: `单个文件请勿超过${maxSize}M,请重新上传`,
icon: 'none'
});
return;
}
this.handleH5Upload(param, file);
}
})
},
handleH5Upload({ url, name = 'file', header, addName, addSize, ...data } = {}, tempFile) {
let fileName = tempFile.name;
let formData = new FormData();
for (let keys in data) { formData.append(keys, data[keys]); }
if (addName) { formData.append(addName, fileName); }
if (addSize) { formData.append(addSize, tempFile.size); }
formData.append(name, tempFile);
this.uploadTask = new XMLHttpRequest();
this.uploadTask.open("POST", url, true);
for (let keys in header) { this.uploadTask.setRequestHeader(keys, header[keys]); }
this.uploadTask.ontimeout = () => {
setTimeout(() => {
this.showTip = false;
return this.errorHandler('请求超时', this.upErr);
}, 1000);
};
this.uploadTask.upload.addEventListener("progress", (event) => {
if (event.lengthComputable) {
this.value = Math.ceil(event.loaded * 100 / event.total);
if (this.value > 100) { this.value = 100; }
this.$forceUpdate();
}
}, false);
this.uploadTask.onreadystatechange = (ev) => {
if (this.uploadTask.readyState == 4) {
console.log('status:' + this.uploadTask.status);
if (this.uploadTask.status == 200) {
return this.handleBack(fileName, this.uploadTask.responseText, tempFile.size);
}
else {
this.showTip = false;
if (this.uploadTask.status == 0) {
console.log('请检查请求头Content-Type与服务端是否匹配,并确认服务端已正确开启跨域');
}
return this.errorHandler('文件上传失败', this.upErr);
}
}
};
this.showTip = true;
this.uploadTask.send(formData);
},
handleWXUpload({ url, name = 'file', header, addName, addSize, ...formData } = {}, tempFile) {
let opt = { url, name, formData, header, filePath: tempFile.path };
if (addName) { opt.formData[addName] = tempFile.name; }
if (addSize) { opt.formData[addSize] = tempFile.size; }
let fileName = tempFile.name;
opt['fail'] = (e) => {
this.showTip = false;
return this.errorHandler('文件上传失败', this.upErr)
};
opt['success'] = (res) => {
if (res.statusCode == 200) {
let data = JSON.parse(res.data);
//可自行添加后台返回状态验证
return this.onCommit(this.$emit('up-success', { fileName, size: tempFile.size, data }));
}
return this.errorHandler('文件上传失败', this.upErr);
};
this.showTip = true;
this.uploadTask = uni.uploadFile(opt);
this.uploadTask && this.uploadTask.onProgressUpdate(({ progress = 0 }) => {
if (progress <= 100) {
this.value = progress;
this.$forceUpdate();
}
});
},
onCloseH5() {
this.showH5 = false;
},
onAbort() {
this.uploadTask && this.uploadTask.abort();
this.showTip = false;
},
downOnAbort() {
this.downloadTask && this.downloadTask.abort();
this.onCommit(false, '已取消');
},
// app+h5返回内容,此处按实际项目修改
handleBack(fileName, str = '{}', size) {
console.log('可根据需求自行修改emit内容,服务端返回:' + str);
try {
str = JSON.parse(str);
} catch (e) {
console.log('Tips: responseText are not JSON');
}
return this.onCommit(this.$emit('up-success', { statusCode: 200, fileName, size, data: str }));
},
/*
上传
*/
upload(param = {}) {
if (!param.url) { this.toast('上传地址不正确'); return; }
if (this.loading) { this.toast('还有个文件玩命处理中,请稍候..'); return; }
// #ifdef APP-PLUS
return this.appChooseFile(param);
// #endif
// #ifdef MP-WEIXIN
return this.wxChooseFile(param);
// #endif
// #ifdef H5
this.h5ChooseFile(param);
// #endif
},
/*
打开文件
*/
open(filePath, fileType) {
let system = uni.getSystemInfoSync().platform;
if (system == 'ios') { filePath = encodeURI(filePath); }
uni.openDocument({
filePath,
fileType: fileType,
success: (res) => { console.log('打开文档成功'); }
});
},
/*
APP自定义保存
*/
plusSaveFile({ url, customName = '', opt }) {
return new Promise((resolve, reject) => {
// 可自行修改参数
// 参数api: http://www.html5plus.org/doc/zh_cn/downloader.html#plus.downloader.DownloadOptions
let downloadOptions = {
method: "GET",
timeout: 120,
retryInterval: 10,
filename: 'file://storage/emulated/0/lFile/' + customName
};
downloadOptions = { ...downloadOptions, ...opt };
this.downloadTask = plus.downloader.createDownload(url, downloadOptions, (d, status) => {
// 下载完成
if (status == 200) {
let tempFilePath = d.filename;
this.value = 100;
this.onCommit(resolve(tempFilePath))
} else {
this.errorHandler('下载失败', reject)
}
this.downloadTask = null;
});
this.downloadTask.addEventListener('statechanged', ({ downloadedSize = 0, state = 0, totalSize = 0 } = {}) => {
if (state === 3) {
let total = totalSize > 0 ? totalSize : fileSize;
let progressVal = Math.ceil(downloadedSize / total * 100);
this.value = progressVal > 100 ? 100 : progressVal;
this.$forceUpdate()
}
}, false);
this.downloadTask.start();
});
},
/*
下载
type: temporary=返回临时地址,save=长期保存到本地
*/
download({ url, type = 'save', customName = '', ...opt }) {
if (this.loading) {
this.toast('还有个文件玩命处理中,请稍候..');
return;
}
this.setdefUI();
// #ifdef APP-PLUS
/* if (type == 'save') {
return this.plusSaveFile({url,customName,opt});
} */
// #endif
return new Promise((resolve, reject) => {
url = encodeURI(url);
this.downloadTask = uni.downloadFile({
url,
...opt,
success: ({ statusCode, tempFilePath }) => {
if (statusCode === 200) {
if (type == 'save') {
uni.saveFile({
tempFilePath,
success: ({ savedFilePath }) => {
console.log('errstatusCodestatusCodestatusCode');
this.onCommit(resolve(savedFilePath))
console.log('errstatusCodestatusCodestatusCode');
},
fail: (err) => {
console.log('下载失败');
this.errorHandler('下载失败', reject)
}
});
}
else {
this.onCommit(resolve(tempFilePath))
}
// #ifdef H5
this.onCommit(resolve(tempFilePath))
// #endif
}
},
fail: () => this.errorHandler('下载失败', reject)
});
this.downloadTask.onProgressUpdate(({ progress = 0 }) => {
if (progress <= 100) {
this.value = progress;
this.$forceUpdate();
}
});
})
},
onCommit(resolve, msg = '执行完毕~') {
this.msg = msg;
this.loading = false;
this.showTip = false;
this.cubgColor = 'rgba(57, 181, 74, 0.5)';
this.uploadTask = null;
this.downloadTask = null;
setTimeout(() => { this.show = false; this.showH5 = false; }, 1500);
return resolve;
},
setdefUI() {
this.cubgColor = this.bgColor;
this.value = 0;
this.loading = true;
this.show = true;
},
upErr(errText) {
this.$emit('up-error', errText);
},
errorHandler(errText, reject) {
this.msg = errText;
this.loading = false;
this.cubgColor = 'rgba(229, 77, 66, 0.5)';
this.uploadTask = null;
this.downloadTask = null;
setTimeout(() => { this.show = false; }, 1500);
return reject(errText);
}
}
}
</script>
<style scoped>
.t-toptips {
width: 100%;
padding: 18upx 30upx;
box-sizing: border-box;
position: fixed;
z-index: 90;
color: #fff;
font-size: 30upx;
left: 0;
display: flex;
align-items: center;
justify-content: center;
word-break: break-all;
opacity: 0;
transform: translateZ(0) translateY(-100%);
transition: all 0.3s ease-in-out;
}
.close {
width: 3em;
text-align: right;
}
.t-top-show {
transform: translateZ(0) translateY(0);
opacity: 1;
}
.flex {
display: flex;
align-items: center;
}
.flex-sub {
flex: 1;
}
.round {
border-radius: 5000upx;
}
/* ==================
进度条
==================== */
.cu-progress {
overflow: hidden;
height: 28upx;
background-color: #ebeef5;
display: inline-flex;
align-items: center;
width: 100%;
}
.cu-progress + view,
.cu-progress + text {
line-height: 1;
}
.cu-progress.xs {
height: 10upx;
}
.cu-progress.sm {
height: 20upx;
}
.cu-progress view {
width: 0;
height: 100%;
align-items: center;
display: flex;
justify-items: flex-end;
justify-content: space-around;
font-size: 20upx;
color: #ffffff;
transition: width 0.6s ease;
}
.cu-progress text {
align-items: center;
display: flex;
font-size: 20upx;
color: #333333;
text-indent: 10upx;
}
.cu-progress.text-progress {
padding-right: 60upx;
}
.cu-progress.striped view {
background-image: linear-gradient(
45deg,
rgba(255, 255, 255, 0.15) 25%,
transparent 25%,
transparent 50%,
rgba(255, 255, 255, 0.15) 50%,
rgba(255, 255, 255, 0.15) 75%,
transparent 75%,
transparent
);
background-size: 72upx 72upx;
}
.cu-progress.active view {
animation: progress-stripes 2s linear infinite;
}
@keyframes progress-stripes {
from {
background-position: 72upx 0;
}
to {
background-position: 0 0;
}
}
</style>
fileUpload index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>文件上传</title>
<script src="vue.min.js"></script>
<script src="axios.min.js"></script>
<!--微信小程序 JS-SDK 如果不需要兼容微信小程序,则无需引用此 JS 文件。 -->
<script type="text/javascript" src="https://res.wx.qq.com/open/js/jweixin-1.4.0.js"></script>
<!-- uni 的 SDK -->
<script type="text/javascript" src="https://js.cdn.aliyun.dcloud.net.cn/dev/uni-app/uni.webview.1.5.2.js"></script>
<!-- 在引用依赖的文件后,需要在 HTML 中监听 UniAppJSBridgeReady 事件触发后,才能安全调用 uni 的 API。-->
<style>
body {
font-family: Arial, sans-serif;
margin: 0;
padding: 0;
background: #f1f1f1;
}
.container {
width: 100%;
margin: 50px auto 0;
}
.container .upload-pannel {
width: 60%;
background: #fff;
border-radius: 10px;
margin: 20px auto 0;
overflow: hidden;
}
.container .upload-pannel .pannel-title {
width: 90%;
margin: 20px auto;
font-size: 15px;
color: #333;
font-weight: bold;
display: block;
}
.container .upload-pannel .file-select {
width: 90%;
height: 13rem;
border: 2px dashed rgb(59, 94, 225);
background: rgba(59, 94, 225, 0.05);
margin: 20px auto;
display: block;
border-radius: 10px;
position: relative;
}
.container .upload-pannel input[type="file"] {
width: 100%;
height: 100%;
opacity: 0;
position: absolute;
left: 0;
top: 0;
}
.container .upload-pannel .upload-icon {
width: 40px;
height: 35px;
display: block;
margin: 0 auto;
line-height: 250px;
}
.container .upload-pannel .upload-icon img {
width: 40px;
height: 35px;
}
.container .upload-pannel .file-select .upload-text {
text-align: center;
display: block;
font-size: 14px;
color: #999;
line-height: 230px;
}
.container .upload-pannel .upload-progress {
width: 90%;
height: 60px;
background: #f1f1f1;
margin: 20px auto;
border-radius: 10px;
overflow: hidden;
}
.container .upload-pannel .upload-progress .progress-bar-container {
position: relative;
width: 90%;
height: 10px;
margin: 25px auto;
background: #f1f1f1;
border-radius: 10px;
overflow: hidden;
}
.container .upload-pannel .upload-progress .progress-bar {
height: 100%;
background: rgb(59, 94, 225);
border-radius: 10px;
transition: width 0.3s ease-in-out;
}
.container .upload-pannel .upload-progress .progress-text {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
font-size: 12px;
color: #fff;
}
.container .upload-pannel .imgPreview {
width: 90%;
margin: 20px auto;
display: block;
}
</style>
</head>
<body>
<div id="app"></div>
<script>
new Vue({
el: '#app',
data() {
return {
fiUrl: '',
uploadProgress: 0,
uploadProgressbg: false,
baseUrl: '',
token: ''
};
},
mounted() {
this.baseUrl = this.getQueryParam('baseUrl');
this.token = this.getQueryParam('token');
},
methods: {
getQueryParam(name) {
let search = window.location.search.substring(1); // 去掉开头的?
let params = search.split('&');
for (let i = 0; i < params.length; i++) {
let pair = params[i].split('=');
if (pair[0] === name) {
return pair[1];
}
}
return null; // 如果没有找到参数,返回null
},
async handleImageUpload(event) {
const file = event.target.files[0];
if (file) {
// 上传图片
this.uploadProgressbg = true;
const formData = new FormData();
formData.append('file', file);
try {
const response = await axios.post(this.baseUrl + '/sys/common/upload', formData, {
headers: {
'X-Access-Token': this.token, // 使用后端要求的头名
},
onUploadProgress: progressEvent => {
// 改变进度条
this.uploadProgress = Math.round((progressEvent.loaded / progressEvent.total) * 100);
},
});
console.log(response, 'responseresponse');
let fileUrl
if (response.data.success) {
fileUrl = response.data.message;
this.fiUrl = fileUrl;
wx.miniProgram.navigateBack({ delta: 1 })
wx.miniProgram.postMessage({ data: { message: '上传成功', url: fileUrl } })
} else {
wx.miniProgram.navigateBack({ delta: 1 })
wx.miniProgram.postMessage({ data: { message: '上传失败' } })
}
} catch (error) {
// 上传失败
console.error('Error uploading image:', error);
wx.miniProgram.navigateBack({ delta: 1 })
wx.miniProgram.postMessage({ data: '上传失败' })
} finally {
// 隐藏进度条
setTimeout(() => {
this.uploadProgress = 0;
this.uploadProgressbg = false;
}, 1500);
}
}
},
},
template: `
<div class="container">
<div class="upload-pannel">
<span class="pannel-title"></span>
<span class="file-select">
<input type="file" accept=".doc,.docx,.ppt,.pdf,.xls,.xlsx" @change="handleImageUpload">
<span class="upload-icon">
<img src="upload.png" />
</span>
<span class="upload-text"></span>
</span>
<div class="upload-progress" v-if="uploadProgressbg == true">
<div class="progress-bar-container" :class="{ active: uploadProgressbg }">
<div class="progress-bar" :style="{ width: uploadProgress + '%' }"></div>
<span class="progress-text" v-if="uploadProgressbg">{{ uploadProgress }}%</span>
</div>
</div>
<img v-if="fiUrl" :src="fiUrl" class="imgPreview">
</div>
</div>`,
});
</script>
</body>
</html>
总结
这个组件由于包含了,文件上传进度条以及预览等功能,所有代码较多。核心代码主要在web-view页面和 fileUpload 文件下index.html
这里也是可以携带token进行文件上传的
web-view中message的到的就是上传接口返回的url
注意:web-view得有路由变化以及页面销毁等才会传参。