由于采用的是Taro3.x+Vue3+NutUI3.X+TSX多端构建开发小程序的,所以先简述下这个解决方案
1、微信小程序-开放式跨端跨框架解决方案
Taro 是一个开放式跨端跨框架解决方案,支持使用 React/Vue/Nerv 等框架来开发 微信 / 京东 / 百度 / 支付宝 / 字节跳动 / QQ / 飞书 小程序 / H5 / RN 等应用。
现如今市面上端的形态多种多样,Web、React Native
、微信小程序等各种端大行其道。当业务要求同时在不同的端都要求有所表现的时候,针对不同的端去编写多套代码的成本显然非常高,这时候只编写一套代码就能够适配到多端的能力就显得极为需要。
Taro
写小程序其实大部分API
还是调取微信的,只是WX.
变成了Taro.
,还对其进行了一定的补充。
1、文件上传(原生开发的话只需要把Taro.改成wx.)
文件上传
js
Taro.chooseMessageFile({
count: props.maxNum,
type: 'file',
success: function(res: any) {
console.log(res.tempFiles, res.tempFiles[0].path)
const suffix = res.tempFiles[0].path.split('.')[1]
if (!props.fileType.includes(suffix)) {
Toast('请选择xls或xlsx文件上传')
return
}
state.fileName = res.tempFiles[0].name
if (props.uploadWay) {//选中文件,暂不上传
state.fileList.push(res.tempFiles[0])
emitData()
} else {//选中文件就上传
Taro.showLoading({
title: '上传中'
})
Taro.uploadFile({
url: baseUrl + `/api/v1/file/${props.uploadType}/upload`, // 仅为示例,非真实的接口地址
filePath: res.tempFiles[0].path,
name: 'file',
header: { Authorization: 'Bearer ' + useUserStore().token },
formData: {
'enterpriseId': props.enterpriseId
},
success(res: any) {
const { success, content } = JSON.parse(res.data)
if (success) state.fileList.push(content)
emitData()
},
complete: function() {
Taro.hideLoading()
}
})
}
}
})
2、文件下载
js
downTemplate().then((res) => {
const { success, content } = res
success && Taro.downloadFile({
url: content, // 仅为示例,并非真实的资源
success: function(res) {
// 只要服务器有响应数据,就会把响应内容写入文件并进入 success 回调,业务需要自行判断是否下载到了想要的内容
if (res.statusCode === 200) {
const filePath = res.tempFilePath
Taro.openDocument({
filePath: filePath,
showMenu: true,
success: function() {
console.log('打开文档成功')
}
})
}
},
complete: function() {
state.downdisabled = false
}
})
}).finally(() => state.downdisabled = false)
3、文件流写入
responseType: 'arraybuffer',
这个别忘了配置
js
// 台账模块-下载模板
export function downTemplate(params) {
return request(
{
url: baseUrl + `/api/v1/tracedata/template/${params.fieldName}`,
method: 'get',
responseType: 'arraybuffer',
params
}
)
}
js
const uploadTemplete = () => {
state.downdisabled = true
downTemplate(state.searchParams).then((res) => {
const fs = Taro.getFileSystemManager() // 全局唯一的文件管理器
const fileName = useUserStore()?.userInfo?.enterpriseName + '_' + useDidShowStore()?.placeInfo?.fieldNameDisplay + '_' + dayjs().format('YYYYMMDD') + '.xlsx'
fs.writeFile({
filePath: Taro.env.USER_DATA_PATH + '/' + fileName, // 这里填文件的名字
data: res,
encoding: 'utf-8',
success() {
Taro.openDocument({
showMenu: true,
filePath: Taro.env.USER_DATA_PATH + '/' + fileName,
success: function() {
state.downdisabled = false
}
})
}
})
}).finally(() => state.downdisabled = false)
}
这里如果想兼容PC端小程序和移动端小程序,需要加上判断,调用不同端的API。
js
Taro.getSystemInfo({
success: (res) => {
// windows | mac为pc端
// android | ios为手机端
if (['windows', 'mac'].includes(res.platform)) {
Taro.saveFileToDisk({
filePath: filePath,
success(res) {
console.log(res)
},
fail(res) {
console.error(res)
}
})
} else {
Taro.openDocument({
showMenu: true,
filePath: filePath,
success: function() {
state.downdisabled = false
}
})
}
}
})
注意:webView方式的H5页面下载文件功能,有时候会被微信浏览器拦截,有时不会。解决方案也很简单,放在小程序内下载,实现方式可以是直接在小程序内也可以是交叉进行。
2、webview内嵌H5解决PC端文件无法上传问题
通过H5的形式,就没有局限性了,可以随意发挥,使用UI框架的上传也好,自己写原生的也简单,我这里用的是京东的NutUI。引入微信的jssdk,实现H5与原生小程序之间的交互。
1、文件上传
js
import {useAttrs, defineComponent, reactive, ref} from 'vue'
import {Uploader, Dialog, Toast} from '@nutui/nutui'
import {getizhuisuUrl, getHeaders} from '@/api'
import {useExpose} from '@/components/it/utils'
import {goBack} from '@/utils'
const icon_upload = require('@/assets/images/izhuisu/icon_upload.png')
export default defineComponent({
name: 'FileUpload',
props: {
prop: {
type: String,
default: ''
},
fetchParams: {
type: Object,
default: () => ({})
},
uploadUrl: {
type: String,
default: ''
},
fileList: {
type: Array,
default: () => []
},
max: {
type: Number,
default: 1
},
maxSize: {
type: Number || String,
default: 20 * 1024 * 1024 // 默认最大5M
},
formData: {
type: Object,
default: () => { }
},
timeoutTime: {
type: Number,
default: 1000 * 120
}
},
setup(props) {
const uploadRef = ref()
const attrs: any = useAttrs()
const state = reactive({
fileList: props.fileList
})
const deleteFile = () => {
uploadRef.value.onDelete()
}
const onSuccess = () => goBack()
const onFailure = ({responseText}) => {
// Toast.fail(JSON.parse(responseText).errors[0].message)
Dialog({
title: '提示',
content: JSON.parse(responseText).errors[0].message,
noCancelBtn: true
})
deleteFile()
}
const beforeUpload = (file) => {
const fileType = ['application/vnd.openxmlformats-officedocument.spreadsheetml.sheet', 'application/vnd.ms-excel']
if (!fileType.includes(file[0].type)) {
Toast.warn('文件格式不正确,仅支持xlsx和xls格式')
return new Promise((resolve) => resolve([]))
} else {
return new Promise((resolve) => resolve([file[0]]))
}
}
const onChange = () => {
console.log(11111)
}
// 获取 tableRef 实例
const getSumbit = () => uploadRef.value.submit()
useExpose({
getSumbit
})
return () => (
<>
<Uploader
autoUpload={false}
ref={uploadRef}
url={getizhuisuUrl(props.uploadUrl)}
accept='.xls,.xlsx'
headers={getHeaders()}
data={props.formData}
maximum={props.max}
vModel:fileList={state.fileList}
with-Credentials='true'
onSuccess={onSuccess}
onFailure={onFailure}
maximize={props.maxSize}
timeout={props.timeoutTime}
{...props}
{...attrs}
upload-icon={icon_upload}
beforeUpload={beforeUpload}
onChange={onChange}
>
</Uploader>
</>
)
}
})
2、文件下载
responseType: 'blob',
这个别忘了配置
3、滑动事件适配
思考
所有的移动端的组件库(比如有赞的VantUI
、京东的nutUI
等),因此默认只适配了移动端设备,这意味着组件只监听了移动端的 touch
事件,没有监听桌面端的mouse
事件。
解决方案
思路很简单,只要让将 mouse
事件转换成对应的 touch
事件,问题不就迎刃而解了。
有赞团队就很贴心,直接安排明白
如果你需要在桌面端使用 移动端组件库(不局限于Vant
,都可以用),可以引入有赞团队提供的 @vant/touch-emulator
,这个库会在桌面端自动将 mouse
事件转换成对应的 touch
事件,使得组件能够在桌面端使用。
- 安装模块
js
npm i @vant/touch-emulator -S
- 引入模块后自动生效
js
import '@vant/touch-emulator';
写在最后
我是凉城a,一个前端,热爱技术也热爱生活。
与你相逢,我很开心。
- 文中如有错误,欢迎在评论区指正,如果这篇文章帮到了你,欢迎点赞和关注😊
- 本文首发于掘金,未经许可禁止转载💌