赞
踩
开发工具:HBuilder(v3.8.7.20230703); 框架:uni-app(vue3);
由于第一次使用uniapp开发APP,开发中遇到app上传图片的问题,这个问题是困扰我时间最长的,查找了各种文章,所以记录一下。
大家肯定和我一样一开始都没有考虑,以为
uni.uploadFile()
可以直接上传到OSS,我替大家试了,不行。
原因:APP上传拿到的不是一个file格式数据,是一个app的临时链接,无法上传到oss,要转换为file格式才可以, 但是转file要使用nodejs中的内置模块,可能是uniapp没有加载nodejs内置模块无法使用,然后可以使用renderjs实现。
renderjs是一个运行在视图层的js, 它只支持app-vue和h5, 主要服务于APP。
- <template>
- <view>
- <uni-file-picker
- v-if="!slots.default"
- v-model="fileList"
- :limit="limit"
- :title="title"
- :readonly="disabled"
- @select="handleSelectImage"
- />
-
- // info:传到renderjs中的参数
- // change:info="uploadFile.tofile" 监听info的变化 。
- <view :info="uploadData" :change:info="uploadFile.tofile"></view>
- </view>
- </template>
-
- // service 层
- <script setup>
- </srcipt>
-
- // module:renderjs模块名称
- <script module="uploadFile" lang="renderjs">
- // data:info的新数据
- // oldValue: 旧数据
- // ownerInstance 可用来向service通信
- tofile (data, oldValue, ownerInstance) {}
- </srcipt>
以下是全部代码
- <template>
- <view>
- <uni-file-picker
- v-if="!slots.default"
- v-model="fileList"
- :limit="limit"
- :title="title"
- :readonly="disabled"
- @select="handleSelectImage"
- />
- <view :info="uploadData" :change:info="uploadFile.tofile"></view>
- </view>
- </template>
-
- <script setup>
- import { watchEffect, ref, useSlots, reactive } from 'vue'
- import { signatureKey } from '@/utils/ali-oss'
- import { getUploadPolicy } from '@/request/oss'
-
- const fileList = ref([])
- const uploadData = reactive({})
- const slots = useSlots()
- const isUpload = ref(false)
-
- const props = defineProps({
- modelValue: {
- type: String,
- default() {
- return ''
- }
- },
- fileType: {
- type: String,
- default() {
- return ''
- }
- },
- limit: {
- type: String,
- default() {
- return '1'
- }
- },
- title: {
- type: String,
- default() {
- return ''
- }
- },
- disabled: {
- type: Boolean,
- default() {
- return false
- }
- }
- })
-
- const emit = defineEmits(['update:modelValue', 'success'])
-
- const formatFiles = (modelValue) => {
- if (!modelValue) {
- return []
- }
- const fileList = modelValue.split(',')
- return fileList.map(item => {
- return {
- name: '',
- key: item,
- extname: 'png',
- url: signatureKey(item)
- }
- })
- }
-
- const handleSuccess = (data, url) => {
- fileList.value.push({
- name: '',
- url,
- key: data.key
- })
- const keyList = []
- fileList.value.forEach(item => {
- keyList.push(item.key)
- })
- emit('update:modelValue', keyList.join(','))
- emit('success', keyList.join(','))
- }
-
- const handleUpload = (fileData) => {
- const file = fileData.file
- const ext = file.name?.split('.')[1]
- const suffix = ext ? `.${ext}` : ''
- const fileType = props.fileType || 'other_file'
- getUploadPolicy({ suffix, fileType })
- .then(({ code, data }) => {
- if(code === 200) {
- // #ifdef APP-PLUS
- Object.assign(uploadData, { ...data, ...file })
- handleSuccess(data, file.path)
- // #endif
- // #ifdef H5
- uni.uploadFile({
- url: data.host,
- file: file,
- formData: {
- 'key': data.key,
- 'policy': data.policy,
- 'OSSAccessKeyId': data.ossAccessKeyId,
- 'success_action_status': '200',
- 'signature': data.signature
- },
- success: ({ statusCode }) => {
- if (statusCode === 200) {
- handleSuccess(data, fileData.url)
- }
- }
- })
- // #endif
- }
- })
- .catch((err) => {
- console.error(err)
- })
- }
-
- const handleSelectImage = ({ tempFiles }) => {
- tempFiles.forEach(item => {
- handleUpload(item)
- })
- }
-
-
- watchEffect(() => {
- if (!isUpload.value) {
- fileList.value = formatFiles(props.modelValue)
- }
- })
- </script>
-
- <script module="uploadFile" lang="renderjs">
- export default {
- methods: {
- tofile (data, oldValue, ownerInstance, instance) {
- if (data && data.path) {
- plus.io.resolveLocalFileSystemURL(data.path, (entry) => {
- entry.file((file) => {
- var fileReader = new plus.io.FileReader()
- fileReader.readAsDataURL(file)
- fileReader.onloadend = (evt) => {
- const base64Data = evt.target.result
- var arr = base64Data.split(',')
- var mime = arr[0].match(/:(.*?);/)[1]
- var bstr = atob(arr[1])
- var n = bstr.length
- var u8arr = new Uint8Array(n)
- while(n--) {
- u8arr[n] = bstr.charCodeAt(n)
- }
- const file = new File([u8arr], data.name, {type: mime})
- this.handleUpload(data, file)
- }
- })
- })
- }
- },
- handleUpload(data, file) {
- const formData = new FormData()
- formData.append('key', data.key)
- formData.append('policy', data.policy)
- formData.append('OSSAccessKeyId', data.ossAccessKeyId)
- formData.append('success_action_status', '200')
- formData.append('signature', data.signature)
- formData.append('file', file)
- // 无法使用uniapp中的上传方法,所以使用原生的上传
- const xhr = new XMLHttpRequest()
- xhr.open('POST', data.host, true)
- xhr.onload = (e) => {
- console.log(e)
- }
- xhr.send(formData)
- xhr.onreadystatechange = () => {
- if(xhr.readyState == 4 && xhr.status == 200) {
- console.log('上传成功!')
- }
- }
- }
- }
- }
- </script>
-
- <style lang="scss" scoped>
- </style>
app上传后的回调
- const handleUpload = (fileData) => {
- const file = fileData.file
- const ext = file.name?.split('.')[1]
- const suffix = ext ? `.${ext}` : ''
- const fileType = props.fileType || 'other_file'
- getUploadPolicy({ suffix, fileType })
- .then(({ code, data }) => {
- if(code === 200) {
- // #ifdef APP-PLUS
- Object.assign(uploadData, { ...data, ...file })
-
- // 强调以下这段代码其实取了巧,它有更好的实现方式是在renderjs xhr上传成功后在回调,用到了
- // renderjs的ownerInstance.callMethod('')实现,具体可以查文档。我为什么没用呢,是因为,
- // 不知道是不是用了vue3的原因,还是uniapp有bug,用不了,不触发service层数据。
- // ------------------------
- handleSuccess(data, file.path)
- // --------------------------
-
- // #endif
- }
- })
- .catch((err) => {
- console.error(err)
- })
- }
结束!!!!!!
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。