图片上传是一个很常见的功能,这里将举例h5、小程序、pc端图片上传。
主要逻辑:通过图片上传组件或api拿到图片信息,上传服务器拿到服务器url
1:h5
这里是base64image的工具函数
function getLocalFilePath(path) {
if (path.indexOf('_www') === 0 || path.indexOf('_doc') === 0 || path.indexOf('_documents') === 0 || path.indexOf('_downloads') === 0) {
return path
}
if (path.indexOf('file://') === 0) {
return path
}
if (path.indexOf('/storage/emulated/0/') === 0) {
return path
}
if (path.indexOf('/') === 0) {
var localFilePath = plus.io.convertAbsoluteFileSystem(path)
if (localFilePath !== path) {
return localFilePath
} else {
path = path.substr(1)
}
}
return '_www/' + path
}
function dataUrlToBase64(str) {
var array = str.split(',')
return array[array.length - 1]
}
var index = 0
function getNewFileId() {
return Date.now() + String(index++)
}
function biggerThan(v1, v2) {
var v1Array = v1.split('.')
var v2Array = v2.split('.')
var update = false
for (var index = 0; index < v2Array.length; index++) {
var diff = v1Array[index] - v2Array[index]
if (diff !== 0) {
update = diff > 0
break
}
}
return update
}
export function pathToBase64(path) {
return new Promise(function(resolve, reject) {
if (typeof window === 'object' && 'document' in window) {
if (typeof FileReader === 'function') {
var xhr = new XMLHttpRequest()
xhr.open('GET', path, true)
xhr.responseType = 'blob'
xhr.onload = function() {
if (this.status === 200) {
let fileReader = new FileReader()
fileReader.onload = function(e) {
resolve(e.target.result)
}
fileReader.onerror = reject
fileReader.readAsDataURL(this.response)
}
}
xhr.onerror = reject
xhr.send()
return
}
var canvas = document.createElement('canvas')
var c2x = canvas.getContext('2d')
var img = new Image
img.onload = function() {
canvas.width = img.width
canvas.height = img.height
c2x.drawImage(img, 0, 0)
resolve(canvas.toDataURL())
canvas.height = canvas.width = 0
}
img.onerror = reject
img.src = path
return
}
if (typeof plus === 'object') {
plus.io.resolveLocalFileSystemURL(getLocalFilePath(path), function(entry) {
entry.file(function(file) {
var fileReader = new plus.io.FileReader()
fileReader.onload = function(data) {
resolve(data.target.result)
}
fileReader.onerror = function(error) {
reject(error)
}
fileReader.readAsDataURL(file)
}, function(error) {
reject(error)
})
}, function(error) {
reject(error)
})
return
}
if (typeof wx === 'object' && wx.canIUse('getFileSystemManager')) {
wx.getFileSystemManager().readFile({
filePath: path,
encoding: 'base64',
success: function(res) {
resolve('data:image/png;base64,' + res.data)
},
fail: function(error) {
reject(error)
}
})
return
}
reject(new Error('not support'))
})
}
export function base64ToPath(base64) {
return new Promise(function(resolve, reject) {
if (typeof window === 'object' && 'document' in window) {
base64 = base64.split(',')
var type = base64[0].match(/:(.*?);/)[1]
var str = atob(base64[1])
var n = str.length
var array = new Uint8Array(n)
while (n--) {
array[n] = str.charCodeAt(n)
}
return resolve((window.URL || window.webkitURL).createObjectURL(new Blob([array], { type: type })))
}
var extName = base64.split(',')[0].match(/data\:\S+\/(\S+);/)
if (extName) {
extName = extName[1]
} else {
reject(new Error('base64 error'))
}
var fileName = getNewFileId() + '.' + extName
if (typeof plus === 'object') {
var basePath = '_doc'
var dirPath = 'uniapp_temp'
var filePath = basePath + '/' + dirPath + '/' + fileName
if (!biggerThan(plus.os.name === 'Android' ? '1.9.9.80627' : '1.9.9.80472', plus.runtime.innerVersion)) {
plus.io.resolveLocalFileSystemURL(basePath, function(entry) {
entry.getDirectory(dirPath, {
create: true,
exclusive: false,
}, function(entry) {
entry.getFile(fileName, {
create: true,
exclusive: false,
}, function(entry) {
entry.createWriter(function(writer) {
writer.onwrite = function() {
resolve(filePath)
}
writer.onerror = reject
writer.seek(0)
writer.writeAsBinary(dataUrlToBase64(base64))
}, reject)
}, reject)
}, reject)
}, reject)
return
}
var bitmap = new plus.nativeObj.Bitmap(fileName)
bitmap.loadBase64Data(base64, function() {
bitmap.save(filePath, {}, function() {
bitmap.clear()
resolve(filePath)
}, function(error) {
bitmap.clear()
reject(error)
})
}, function(error) {
bitmap.clear()
reject(error)
})
return
}
if (typeof wx === 'object' && wx.canIUse('getFileSystemManager')) {
var filePath = wx.env.USER_DATA_PATH + '/' + fileName
wx.getFileSystemManager().writeFile({
filePath: filePath,
data: dataUrlToBase64(base64),
encoding: 'base64',
success: function() {
resolve(filePath)
},
fail: function(error) {
reject(error)
}
})
return
}
reject(new Error('not support'))
})
}
2.以taro小程序为例
微信小程序把chooseImage给更新成chooseMedia,将视频与图片合二为一。
// 不可使用promise/async异步写法
export function authSetting(scope, succFn, errFn) {
Taro.getSetting({
success(res) {
const result = res.authSetting[isWeixin ? `scope.${scope}` : `${scope}`]
if (isWeixin) {
if (result === undefined) {
Taro.authorize({
scope: `scope.${scope}`
}).then(succFn, errFn)
} else if (!result) {
Taro.openSetting().then(succFn, errFn)
} else {
succFn()
}
} else if (isAlipay) {
// const alipayScope = {
// "album": "album",
// "writePhotosAlbum": "album"
// }
if (result === false) {
Taro.openSetting().then(succFn, errFn)
} else {
succFn()
}
}
},
fail(res) {
console.error(res)
}
})
}
上传图片服务器的函数
import Taro from '@tarojs/taro'
import req from '@/api/req'
import S from '@/spx'
import { isAlipay, getAppId, exceedLimit, isWeixin } from '@/utils'
// import * as qiniu from 'qiniu-js'
const getToken = (params) => {
return req.get('espier/image_upload_token', params)
}
// const uploadURLFromRegionCode = (code) => {
// switch(code) {
// case 'z0': return'https://up.qiniup.com'
// case 'z1': return 'https://up-z1.qiniup.com'
// case 'z2': return 'https://up-z2.qiniup.com'
// case 'na0': return 'https://up-na0.qiniup.com'
// case 'as0': return 'https://up-as0.qiniup.com'
// default: console.error('please make the region is with one of [z0, z1, z2, na0, as0]')
// }
// }
const upload = {
aliUpload: async (item, tokenRes) => {
const { accessid, dir, host, policy, signature, filetype } = tokenRes
const filename = item.url.slice(item.url.lastIndexOf('/') + 1)
const updata = {
url: host,
filePath: item.url,
name: 'file',
withCredentials: false,
formData: {
name: filename,
key: `${dir}`,
policy: policy,
OSSAccessKeyId: accessid,
// 让服务端返回200
signature: signature,
success_action_status: '200'
// 服务端回调
// callback: callback
},
// fileType: 'image',
fileType: filetype,
header: {
'Content-Type': 'application/x-www-form-urlencoded', // 只能是这种形式
},
fail: (err) => {
// debugger
// console.log('aliUpload:host', host)
console.log('aliUpload:Taro.uploadFile', err)
}
}
// console.log('upload:updata', updata)
// debugger
try {
const res = await Taro.uploadFile(updata)
// console.log('---aliUpload-upload:res', res)
// console.log('---aliUpload-:dir', host, dir)
if (!res) {
return false
}
return {
url: `${host}${dir}`,
filetype
}
} catch (e) {
throw new Error(`aliUpload:${e}`)
}
},
qiNiuUpload: async (item, tokenRes) => {
const { token, key, domain, host, filetype } = tokenRes
const uploadFile = isAlipay ? my.uploadFile : Taro.uploadFile
try {
const { data } = await uploadFile({
url: host,
filePath: item.url,
// fileType: 'image',
fileType: filetype,
withCredentials: false,
[isAlipay ? 'fileName' : 'name']: 'file',
formData: {
'token': token,
'key': key
}
})
const imgData = JSON.parse(data)
if (!imgData.key) {
return false
}
return {
url: `${domain}/${imgData.key}`,
filetype
}
} catch (e) {
console.error(e)
throw new Error(e)
}
},
localUpload: async (item, tokenRes) => {
const { filetype, domain } = tokenRes
const filename = item.url.slice(item.url.lastIndexOf('/') + 1)
let header = {
Authorization: `Bearer ${S.getAuthToken()}`,
}
if (isWeixin) {
header['authorizer-appid'] = getAppId()
}
try {
const res = await Taro.uploadFile({
url: `${req.baseURL}espier/uploadlocal`,
filePath: item.url,
header,
withCredentials: false,
name: 'images',
formData: {
name: filename,
filetype
}
})
const data = JSON.parse(res.data)
const { image_url } = data.data
if (!image_url) {
return false
}
return {
url: `${domain}/${image_url}`,
filetype
}
} catch (e) {
throw new Error(e)
}
},
awsUpload: async (item, tokenRes) => {
const {
formInputs = {
XAmzCredential: '',
XAmzAlgorithm: '',
XAmzDate: '',
Policy: '',
XAmzSignature: '',
key: ''
},
formAttributes = {
action: ''
},
filetype
} = tokenRes
try {
const res = await Taro.uploadFile({
url: formAttributes.action,
filePath: item.url,
name: 'file',
formData: {
key: formInputs.key,
'X-Amz-Credential': formInputs.XAmzCredential,
'X-Amz-Algorithm': `AES256`,
Policy: formInputs.Policy,
'X-Amz-Algorithm': formInputs.XAmzAlgorithm,
'X-Amz-Date': formInputs.XAmzDate,
'X-Amz-Signature': formInputs.XAmzSignature
}
})
const { Location } = res.header
if (!Location) {
return false
}
return {
url: Location,
filetype,
thumb: item.thumb
}
} catch (e) {
throw new Error(e)
}
}
}
const getUploadFun = (dirver) => {
switch (dirver) {
case 'oss':
return 'aliUpload'
case 'local':
return 'localUpload'
case 'aws':
return 'awsUpload'
default:
return 'qiNiuUpload'
}
}
// 返回对应上传方式
const uploadImageFn = async (imgFiles, filetype = 'image') => {
console.log('---imgFiles---', imgFiles)
const imgs = []
for (const item of imgFiles) {
if (!item.file) {
if (item.url) {
imgs.push(item)
}
continue
}
if (exceedLimit(item.file)) {
Taro.showToast({
title: '文件大小超出最大限制,请压缩后再上传',
icon: 'none'
})
break
}
try {
const filename = item.url.slice(item.url.lastIndexOf('/') + 1)
const { driver, token } = await getToken({ filetype, filename })
const uploadType = getUploadFun(driver)
// console.log('----uploadType----', uploadType)
let img = await upload[uploadType](item, { ...token, filetype: item.fileType || filetype })
if (filetype == 'videos' && item.thumb) {
const _thumb = {
url: item.thumb
}
const thumbFileName = _thumb.url.slice(_thumb.url.lastIndexOf('/') + 1)
const thumbRes = await getToken({ filetype: 'image', filename: thumbFileName })
const thumbUploadType = getUploadFun(thumbRes.driver)
const thumbImg = await upload[thumbUploadType]({ url: _thumb.url }, { ...thumbRes.token, filetype: 'image' })
if(thumbImg) {
img['thumb'] = thumbImg.url
}
}
console.log('---uploadImageFn---', img)
if (!img || !img.url) {
continue
}
imgs.push(img)
} catch (err) {
console.error('---uploadImageFn---', err.message)
}
}
// console.log('---uploadImageFn---2', imgs)
return imgs
}
export default {
uploadImageFn
}
3:pc后台
直接上elementui就行,拿到图片信息上传服务器即可
https://element.eleme.cn/#/zh-CN/component/upload#yong-hu-tou-xiang-shang-chuan