最近在做一個新項(xiàng)目窃这,用到了taro + react hooks + oss小程序上傳。今天就來分享一下其中的技術(shù)萝毛,目前來看楷力,taro+ react hooks做的小程序很多框架不兼容,尤其是UI框架锌奴,能夠打包成功的很少兽狭。試了只有@nutui/nutui-react-taro 和?taro-ui@3.1.0-beta.2在小程序執(zhí)行時打包成功,當(dāng)然了鹿蜀,小程序只需要在微信開發(fā)者工具上傳即可箕慧,不需要打包,之前在這里的糾結(jié)的原因是習(xí)慣了build茴恰,尷尬了颠焦。
1、按照taro官方文檔構(gòu)建一個新項(xiàng)目往枣,config配置添加別名配置如下:
alias: {
'@': path.resolve(__dirname, '..', 'src'),
? '@/images': path.resolve(__dirname, '..', 'src/images'),
? '@/assets': path.resolve(__dirname, '..', 'src/assets'),
? '@/components': path.resolve(__dirname, '..', 'src/components'),
? //'@/constants': path.resolve(__dirname, '..', 'src/constants'),
//'@/reducers': path.resolve(__dirname, '..', 'src/reducers'),
? '@/common': path.resolve(__dirname, '..', 'src/common'),
? '@/utils': path.resolve(__dirname, '..', 'src/utils')
},
2伐庭、把需要調(diào)用的api封裝在src/api
import { toQueryString }from '@/utils/filter'
import service from '@/utils/request';
//特殊請求加上這段編碼
const otherHeader = {'Content-Type':'application/x-www-form-urlencoded', 'Accept':'*/*' }
//獲取oss的信息
export const ossGetAccessUrl = (params, headers) => {
return service({
method:'GET',
? ? url:'/oss/token',
? ? data: params,
? ? headers: headers
})
}
3、把全局主題色封裝在common/theme.scss下
@charset "UTF-8";
//默認(rèn)全局背景主題色!default
$default-background:#F6F6F7;
//默認(rèn)字體分冈、按鈕背景主題色
$default-primary:#52A86A;
4圾另、把全局組件封裝在components下
5、把需要過濾的封裝在utils/filter下
// 將一個對象轉(zhuǎn)成QueryString
export const toQueryString = (obj) => {
if (!obj)return "";
? ? return cleanArray(
Object.keys(obj).map(key => {
if (obj[key] ===undefined)return "";
? ? ? ? ? ? return encodeURIComponent(key) +"=" +encodeURIComponent(obj[key]);
? ? ? ? })
).join("&");
}
6雕沉、把請求攔截封裝在utils/request
import Taro from '@tarojs/taro'
const baseURL ='https://xxx.xxx.com/'
let token ='xxxxxxxx'
let flag =true;
export const service = (parmas) => {
parmas.headers['token'] = token;
? let result =new Promise((resolve, reject) => {
Taro.request({
url: baseURL + parmas.url,?
? ? ? data: parmas.parmas,
? ? ? method:parmas.method ,
? ? ? header: {
...{
'content-type':'application/json' // 默認(rèn)值
? ? ? ? }, ...parmas.headers
? ? ? },
? ? ? success:function (response) {
if (response.statusCode && response.statusCode !==200) {
if (flag) {
Taro.showToast({
title:JSON.stringify(response.data.message),
? ? ? ? ? ? ? icon:'none'
? ? ? ? ? ? })
flag =false;
? ? ? ? ? ? setTimeout(() => {
flag =true;
? ? ? ? ? ? }, 1000)
}
}
if (response.statusCode ===200) {
resolve(response.data)
}else {
reject();
? ? ? ? }
},
? ? ? fail(e:any) {
let message ="";
? ? ? ? switch (e.status) {
case 400:
message ="請求錯誤";
break;
? ? ? ? ? case 401: {
message ="未授權(quán)集乔,請登錄";
break;
? ? ? ? ? }
case 403:
message ="沒有權(quán)限,拒絕訪問";
break;
? ? ? ? ? case 404:
message =`請求地址出錯`;
break;
? ? ? ? ? case 500:
message ="服務(wù)器內(nèi)部錯誤";
break;
? ? ? ? ? case 501:
message ="服務(wù)未實(shí)現(xiàn)";
break;
? ? ? ? ? case 502:
message ="網(wǎng)關(guān)錯誤";
break;
? ? ? ? ? case 503:
message ="服務(wù)不可用";
break;
? ? ? ? ? case 504:
message ="網(wǎng)關(guān)超時";
break;
? ? ? ? ? case 505:
message ="HTTP版本不受支持";
break;
? ? ? ? ? default:
break;
? ? ? ? }
if (flag) {
Taro.showToast({
title: message,
? ? ? ? ? ? icon:'none'
? ? ? ? ? })
flag =false;
? ? ? ? ? setTimeout(() => {
flag =true;
? ? ? ? ? }, 1000)
}
reject(e)
}
})
})
return result;
}
下面來講封裝小程序上傳圖片到oss坡椒,因?yàn)樾〕绦蛏蟼鞯膱D片與h5或web端不一樣扰路,沒有file的概念,就需要看阿里云文檔踩坑
1倔叼、封裝stsToken汗唱,需要通過加密等方式得到signature,policy丈攒,x-oss-security-token
import cryptofrom 'crypto-js';
import {Base64}from 'js-base64';
// 計(jì)算簽名渡嚣。
function computeSignature(accessKeySecret, canonicalString) {
return crypto.enc.Base64.stringify(crypto.HmacSHA1(canonicalString, accessKeySecret));
}
const date =new Date();
date.setHours(date.getHours() +1);
const policyText = {
expiration: date.toISOString(), // 設(shè)置policy過期時間。
? conditions: [
// 限制上傳大小。
? ? ["content-length-range", 0, 1024 *1024 *1024],
? ],
};
export const getFormDataParams =async (credentials) => {
const policy = Base64.encode(JSON.stringify(policyText))// policy必須為base64的string识椰。
? const signature =computeSignature(credentials.AccessKeySecret, policy)
const formData = {
OSSAccessKeyId: credentials.AccessKeyId,
? ? signature,
? ? policy,
? ? 'x-oss-security-token': credentials.SecurityToken
? }
return formData
}
2绝葡、封裝Taro.uploadFile上傳方法,傳入host腹鹉、signature藏畅、OSSAccessKeyId、policy功咒、key愉阎、filePath
import Taro from "@tarojs/taro";
export const wxUpload = (data) => {
const host = data.host;
? const signature = data.signature;
? const ossAccessKeyId = data.OSSAccessKeyId;
? const policy = data.policy;
? const key = data.key;
? const securityToken = data['x-oss-security-token'];
? const filePath = data.filePath; // 待上傳文件的文件路徑。
? let result =new Promise((resolve, reject) => {
Taro.uploadFile({
url: host, // 開發(fā)者服務(wù)器的URL力奋。
? ? ? filePath: filePath,
? ? ? name:'file', // 必須填file榜旦。
? ? ? formData: {
name: filePath,
? ? ? ? key,
? ? ? ? policy,
? ? ? ? OSSAccessKeyId: ossAccessKeyId,
? ? ? ? signature,
? ? ? ? success_action_status:"200",
? ? ? ? 'x-oss-security-token': securityToken// 使用STS簽名時必傳。
? ? ? },
? ? ? success: (res) => {
console.log(res)
if (res.statusCode ===200) {
Taro.showToast({title:'上傳成功', icon:'none'})
resolve(host +'/' + key);
? ? ? ? }
},
? ? ? fail: err => {
reject(null)
Taro.showToast({title:'上傳失敗', icon:'none'})
return null;
? ? ? }
});
? })
return result;
}
3景殷、封裝osstoken獲取以及圖片上傳調(diào)用溅呢,在選完圖片后會調(diào)用一次ossGetAccessUrl,可優(yōu)化為進(jìn)入首頁調(diào)用猿挚,放在dva中緩存起來ossGetAccessUrl咐旧,考慮到oss的token可能會失效,所以我這里每次上傳都調(diào)用一次
import {randomString, filterUTCNo}from './filter'
import OSS from 'ali-oss';
import Taro from "@tarojs/taro";
import {getFormDataParams}from './sts'
import {wxUpload}from './wxUpload'
import {ossGetAccessUrl}from '@/api/home'
class MyUploadAdapterAll {
constructor(params) {
// 要在上載期間使用的文件加載器實(shí)例
? ? this.file = params.file
? ? this.ossGetAccessUrlData = {}
}
async getAccessUrl() {
if (!this.file) {
return
? ? }
try {
Taro.showLoading()
let res =await ossGetAccessUrl({}, {})
Taro.hideLoading()
if (res.code ===200) {
? ? ? ? let dataParams:any =await getFormDataParams({
AccessKeySecret: res.data.accessKeySecret,
? ? ? ? ? AccessKeyId: res.data.accessKeyId,
? ? ? ? ? SecurityToken: res.data.securityToken,
? ? ? ? })
dataParams.key =`${filterUTCNo(new Date())}/${randomString(8)}_${Date.now()}.${this.file.split('.')[this.file.split('.').length -1]}`
? ? ? ? dataParams.host ='https://' + res.data.bucket +'.' + res.data.endPoint.split('//')[1];
? ? ? ? dataParams.filePath =this.file;
? ? ? ? console.log(dataParams)
return await wxUpload(dataParams);
? ? ? }
}catch (e) {
? ? ? console.log(e)
}
}
}
export default MyUploadAdapterAll
4绩蜻、在頁面中引入調(diào)用
import MyUploadAdapterAllfrom "@/utils/uploadAll";
Taro.chooseImage({
count:1, // 默認(rèn)9
? sizeType: ['original', 'compressed'], // 可以指定是原圖還是壓縮圖铣墨,默認(rèn)二者都有
? sourceType: ['album', 'camera'], // 可以指定來源是相冊還是相機(jī),默認(rèn)二者都有办绝,在H5瀏覽器端支持使用 `user` 和 `environment`分別指定為前后攝像頭
? success:async (res) => {
console.log(res)
const myUploadAdapter =new MyUploadAdapterAll({
dir:'dev',
? ? ? file: res.tempFilePaths[0]
})
let url:string =await myUploadAdapter.getAccessUrl()
if (url) {
console.log(url)
}
}
})