Taro小程序dva框架開(kāi)發(fā)學(xué)習(xí)

Taro小程序dva框架開(kāi)發(fā)學(xué)習(xí)

本篇介紹的是Taro小程序開(kāi)發(fā),僅供學(xué)習(xí)參考。使用的框架是Taro(3.3.9)+dva+Taro UI架構(gòu)開(kāi)發(fā),其中封裝了dva框架來(lái)管理整個(gè)應(yīng)用的state,基于Taro UI進(jìn)行組建開(kāi)發(fā),封裝了網(wǎng)絡(luò)請(qǐng)求方法(大部分借鑒網(wǎng)絡(luò)),網(wǎng)絡(luò)返回值進(jìn)行了處理,方便數(shù)據(jù)處理。

Taro鏈接:https://taro-docs.jd.com/taro/docs/README/index.html

Taro UI鏈接:https://taro-ui.jd.com/#/docs/introduction

Taro Demo鏈接(Gitee):TaroDvaDemo: Taro+dva demo

Taro Demo鏈接(Github):https://github.com/coffeelife/TaroDvaDemo.git

Taro新舊版本遷移說(shuō)明:https://taro-docs.jd.com/taro/docs/next/migration

項(xiàng)目組成介紹

  • UI:Taro UI和原生組件組成

  • dva:使用redux來(lái)進(jìn)行state同意管理,網(wǎng)絡(luò)請(qǐng)求過(guò)程封裝etc

  • http.js封裝taro請(qǐng)求,統(tǒng)一處理參數(shù)和返回結(jié)果

  • 版本詳情

  • "dependencies": {
        "@babel/runtime": "^7.7.7",
        "@tarojs/async-await": "^2.2.10",
        "@tarojs/cli": "3.3.9",
        "@tarojs/components": "3.3.9",
        "@tarojs/react": "3.3.9",
        "@tarojs/redux-h5": "^2.2.10",
        "@tarojs/runtime": "3.3.9",
        "@tarojs/taro": "3.3.9",
        "babel-runtime": "^6.26.0",
        "dva-core": "^1.6.0-beta.7",
        "dva-loading": "^3.0.22",
        "jsrsasign": "^10.4.1",
        "lodash": "4.17.15",
        "nervjs": "^1.5.7",
        "react": "^17.0.0",
        "react-dom": "^17.0.0",
        "react-redux": "^7.2.5",
        "redux": "^4.1.1",
        "redux-logger": "^3.0.6",
        "redux-thunk": "^2.3.0",
        "regenerator-runtime": "^0.13.9",
        "taro-ui": "^3.0.0-alpha.3",
        "vconsole": "^3.9.1"
      },
    

說(shuō)明

因?yàn)槠綍r(shí)都是使用dva+antd開(kāi)發(fā)網(wǎng)頁(yè)、dva+antd mobile開(kāi)發(fā)手機(jī)網(wǎng)頁(yè)、dva+react native開(kāi)發(fā)手機(jī)app,所以在考慮這個(gè)框架的時(shí)候會(huì)在想自己如何無(wú)感知來(lái)切換到小程序開(kāi)發(fā)當(dāng)中,所以就像使用Taro(react) + dva的方式來(lái)開(kāi)發(fā)小程序,然后Taro提供了自己的UI庫(kù)Taro UI,所以順便使用taro UI作為組件庫(kù)。

開(kāi)發(fā)前準(zhǔn)備

taro cli工具安裝(copy官網(wǎng))

# 使用 npm 安裝 CLI
$ npm install -g @tarojs/cli

# OR 使用 yarn 安裝 CLI
$ yarn global add @tarojs/cli

# OR 安裝了 cnpm,使用 cnpm 安裝 CLI
$ cnpm install -g @tarojs/cli

項(xiàng)目初始化(copy官網(wǎng))

taro init mypp

[圖片上傳失敗...(image-17a4dd-1642501786545)]

項(xiàng)目目錄結(jié)構(gòu)

[圖片上傳失敗...(image-d0abae-1642501786545)]

pages//目錄頁(yè)面目錄
app.config,js//目錄主配置文件
app.js//主入口文件
app.less//主樣式文件
project.config.js//小程序配置文件
package.json依賴(lài)配置文件

project.config.js將該文件的appid改成自己的appid

{
    "miniprogramRoot": "dist/",
    "projectname": "myapp",
    "description": "測(cè)試app",
    "appid": "自己的appId",
    "setting": {
        "urlCheck": true,
        "es6": false,
        "postcss": false,
        "preloadBackgroundData": false,
        "minified": false,
        "newFeature": true,
        "autoAudits": false,
        "coverView": true,
        "showShadowRootInWxmlPanel": false,
        "scopeDataCheck": false,
        "useCompilerModule": false
    },
    "compileType": "miniprogram",
    "simulatorType": "wechat",
    "simulatorPluginLibVersion": {},
    "condition": {}
}

npm run dev:weapp運(yùn)行查看效果

[圖片上傳失敗...(image-5667e7-1642501786545)]

dva框架的搭建

安裝redux、 react-redux 等依賴(lài)包(老版)

npm install --save react-redux

npm install --save redux @tarojs/redux @tarojs/redux-h5 redux-thunk redux-logger

安裝redux、 react-redux 等依賴(lài)包(新版)

Taro新舊版本遷移說(shuō)明:Menu

使用第三方 React庫(kù)#
如果你需要引入 React 相關(guān)生態(tài)的庫(kù),直接通過(guò) npm install 安裝然后引入使用即可,Taro 不會(huì)再維護(hù)類(lèi)似于 taro-redux 、taro-mobx 之類(lèi)的庫(kù)。

// 當(dāng)使用了 JSX 時(shí),babel 會(huì)隱式地調(diào)用 React.createElement
// 因此只要你使用了 JSX,就要把 React 或 Nerv 引入
import React from 'react'
import { useSelector }  from 'react-redux'
// 如果是使用的是 Nerv
// import { useSelector }  from 'nerv-redux'
function Excited () {
  const counter = useSelector(state => state.counter)
  return ...
}
npm install --save react-redux

npm install --save redux @tarojs/redux @tarojs/redux-h5 redux-thunk redux-logger

安裝dva

dva-core:封裝了 redux 和 redux-saga 的一個(gè)插件

dva-loading:管理頁(yè)面的 loading 狀態(tài)

npm install --save dva-core dva-loading

package.json依賴(lài)詳情

"dependencies": {
    "@babel/runtime": "^7.7.7",
    "@tarojs/cli": "3.3.9",
    "@tarojs/components": "3.3.9",
    "@tarojs/react": "3.3.9",
    "@tarojs/redux": "^2.2.10",
    "@tarojs/redux-h5": "^2.2.10",
    "@tarojs/runtime": "3.3.9",
    "@tarojs/taro": "3.3.9",
    "dva-core": "^1.6.0-beta.7",
    "dva-loading": "^3.0.22",
    "lodash": "4.17.15",
    "react": "^17.0.0",
    "react-dom": "^17.0.0",
    "react-redux": "^7.2.6",
    "redux": "^4.1.2",
    "redux-logger": "^3.0.6",
    "redux-thunk": "^2.4.0",
    "taro-ui": "^3.0.0-alpha.3"
  },

在項(xiàng)目中配置dva

src目錄下新建一個(gè)utils目錄,新建一個(gè)dva.js文件,文件代碼如下

import { create } from 'dva-core';
import { createLogger } from 'redux-logger';
import createLoading from 'dva-loading';

let app;
let store;
let dispatch;

function createApp(opt) {
  // redux日志
  // opt.onAction = [createLogger()];
  app = create(opt);
  app.use(createLoading({}));

  if (!global.registered) opt.models.forEach(model => app.model(model));
  global.registered = true;
  app.start();

  store = app._store;
  app.getStore = () => store;

  dispatch = store.dispatch;

  app.dispatch = dispatch;
  return app;
}

export default {
  createApp,
  getDispatch() {
    return app.dispatch;
  }
}

src下新建目錄models目錄,里面新建一個(gè)默認(rèn)的index.jsmodel.js文件

index.js

import model from "./model"
export default [model];

model.js

import * as indexApi from './service';

 export default {
   namespace: 'index',
   state: {

   },

   effects: {
     * effectsDemo(_, { call, put }) {
       const { status, data } = yield call(indexApi.demo, {});
       if (status === 'ok') {
         yield put({ type: 'save',
           payload: {
             topData: data,
           } });
       }
     },
   },

   reducers: {
     save(state, { payload }) {
       return { ...state, ...payload };
     },
   },

 };

src下新建service文件夾,在目錄下新建index.js文件

service.js文件

import httpRequest from '../../utils/http';

 export const demo = (data) => {
   return httpRequest.get("",data);
 };

app.js改造

utils下的dva.js引入,然后使用dvamodel

app.js

import "@tarojs/async-await";
import React, { Component } from "react";
import dva from "./utils/dva";
import models from "./models";
import { Provider } from "react-redux";
import "./app.less";

const dvaApp = dva.createApp({
  initialState: {},
  models: models
});
const store = dvaApp.getStore();
// 如果需要在 h5 環(huán)境中開(kāi)啟 React Devtools
// 取消以下注釋?zhuān)?// if (process.env.NODE_ENV !== 'production' && process.env.TARO_ENV === 'h5')  {
//   require('nerv-devtools')
// }

export default class App extends Component {
  config={}

  componentDidMount() {}

  componentDidShow() {}

  componentDidHide() {}

  componentDidCatchError() {}

  // this.props.children 是將要會(huì)渲染的頁(yè)面
  render() {
    return (
      <Provider store={store}>
        {this.props.children}
      </Provider>
    );
  }
}

新建loginindex目錄然后新建對(duì)應(yīng)的less、js和config.js文件,如圖

login下的index.js文件

import React, { Component } from "react";
import Taro from "@tarojs/taro";
import { View, Text, Button } from "@tarojs/components";
import "./index.less";
import { connect } from "react-redux";
import { AtButton } from "taro-ui";

@connect(({ index }) => ({
  index
}))
export default class Login extends Component {
  componentDidMount() {
    console.log(this.props);
  }

  goMain = () => {
    Taro.redirectTo({ url: "/pages/index/index?a=1&b=2&c=3" });
  };

  render() {
    return (
      <View className="login-page">
        登錄頁(yè)面
        <Button className="loginBtn" onClick={this.goMain}>
          登錄
        </Button>
      </View>
    );
  }
}

index下的index.js文件

import React, { Component } from "react";
import Taro, { getCurrentInstance } from "@tarojs/taro";
import { View, Text, OpenData, Button, Textarea } from "@tarojs/components";
import { connect } from "react-redux";
import "./index.less";

@connect(({ index }) => ({
  index
}))
export default class Index extends Component {
  state = {
    userInfo: {},
    hasUserInfo: false
  };

  componentDidMount = () => {
    Taro.hideHomeButton();
    let { router } = getCurrentInstance();
    let { a, b, c } = router.params;
    console.log(this.props, router, a, b, c);
  };

  getUserProfile = () => {
    // 推薦使用wx.getUserProfile獲取用戶(hù)信息,開(kāi)發(fā)者每次通過(guò)該接口獲取用戶(hù)個(gè)人信息均需用戶(hù)確認(rèn)
    // 開(kāi)發(fā)者妥善保管用戶(hù)快速填寫(xiě)的頭像昵稱(chēng),避免重復(fù)彈窗
    Taro.getUserProfile({
      desc: "用于完善會(huì)員資料", // 聲明獲取用戶(hù)個(gè)人信息后的用途,后續(xù)會(huì)展示在彈窗中,請(qǐng)謹(jǐn)慎填寫(xiě)
      success: res => {
        this.setState(
          {
            userInfo: res.userInfo,
            hasUserInfo: true
          },
          () => {
            Taro.showModal({
              title: "用戶(hù)信息",
              content: JSON.stringify(res.userInfo),
              showCancel: false,
              confirmText: "確定"
            });
          }
        );
      }
    });
  };

  render() {
    let { hasUserInfo, userInfo } = this.state;
    return (
      <View className="index-page">
        <View className="userInfo">
          <OpenData className="userAvatar" type="userAvatarUrl" />
          <View className="userDetail">
            <OpenData type="userNickName" lang="zh_CN" />
            <View>
              <OpenData type="userGender" lang="zh_CN" />{" "}
              <OpenData type="userCountry" lang="zh_CN" />{" "}
              <OpenData type="userProvince" lang="zh_CN" />{" "}
              <OpenData type="userCity" lang="zh_CN" />
            </View>
          </View>
        </View>
        <Button className="userBtn" onClick={this.getUserProfile}>
          獲取用戶(hù)信息
        </Button>
      </View>
    );
  }
}

index的主文件中打印this.props就可以看到對(duì)應(yīng)的state數(shù)據(jù),這里的獲取上一頁(yè)傳遞使用過(guò)let { router } = getCurrentInstance();let { a, b, c } = router.params;來(lái)獲取。這樣dva框架就已經(jīng)加入到小程序當(dāng)中,就可以像使用網(wǎng)頁(yè)開(kāi)發(fā)的思維來(lái)開(kāi)發(fā)小程序。

[圖片上傳失敗...(image-9fbb73-1642501786544)]

taro網(wǎng)絡(luò)請(qǐng)求的封裝

此處借鑒的是網(wǎng)上的demo,可以根據(jù)自己的需求來(lái)進(jìn)行開(kāi)發(fā)調(diào)整。主要設(shè)計(jì)請(qǐng)求方式get、post、put、delete的封裝,攔截器的封裝、返回結(jié)果的封裝,統(tǒng)一返回taro.request這部分我們會(huì)做修改,上代碼

http.js

import Taro from "@tarojs/taro";
import getBaseUrl from "./baseUrl";
import interceptors from "./interceptors";

interceptors.forEach(interceptorItem => Taro.addInterceptor(interceptorItem));

class httpRequest {
  baseOptions(params, method = "GET") {
    let { url, data } = params;
    const BASE_URL = getBaseUrl(url);
    let contentType = "application/json";
    contentType = params.contentType || contentType;
    const option = {
      url: BASE_URL + url, //地址
      data: data, //傳參
      method: method, //請(qǐng)求方式
      timeout: 50000, // 超時(shí)時(shí)間
      header: {
        "content-type": contentType,
        Authorization: Taro.getStorageSync("Authorization")
      }
    };
    return Taro.request(option);
  }

  get(url, data = "") {
    let option = { url, data };
    return this.baseOptions(option);
  }

  post(url, data, contentType) {
    let params = { url, data, contentType };
    return this.baseOptions(params, "POST");
  }

  put(url, data = "") {
    let option = { url, data };
    return this.baseOptions(option, "PUT");
  }

  delete(url, data = "") {
    let option = { url, data };
    return this.baseOptions(option, "DELETE");
  }
}

export default new httpRequest();

攔截器封裝interceptors.js

import Taro from "@tarojs/taro"
import { pageToLogin } from "./utils"
import { HTTP_STATUS } from './config'

const customInterceptor = (chain) => {

  const requestParams = chain.requestParams

  return chain.proceed(requestParams).then(res => {
    // 只要請(qǐng)求成功,不管返回什么狀態(tài)碼,都走這個(gè)回調(diào)
    if (res.statusCode === HTTP_STATUS.NOT_FOUND) {
      return Promise.reject("請(qǐng)求資源不存在")

    } else if (res.statusCode === HTTP_STATUS.BAD_GATEWAY) {
      return Promise.reject("服務(wù)端出現(xiàn)了問(wèn)題")

    } else if (res.statusCode === HTTP_STATUS.FORBIDDEN) {
      Taro.setStorageSync("Authorization", "")
      pageToLogin()
      // TODO 根據(jù)自身業(yè)務(wù)修改
      return Promise.reject("沒(méi)有權(quán)限訪(fǎng)問(wèn)");

    } else if (res.statusCode === HTTP_STATUS.AUTHENTICATE) {
      Taro.setStorageSync("Authorization", "")
      pageToLogin()
      return Promise.reject("需要鑒權(quán)")

    } else if (res.statusCode === HTTP_STATUS.SUCCESS) {
      return res.data

    }
  })
}

// Taro 提供了兩個(gè)內(nèi)置攔截器
// logInterceptor - 用于打印請(qǐng)求的相關(guān)信息
// timeoutInterceptor - 在請(qǐng)求超時(shí)時(shí)拋出錯(cuò)誤。
const interceptors = [customInterceptor, Taro.interceptors.logInterceptor]

export default interceptors

獲取鏈接的方式baseUrl.js

const getBaseUrl = (url) => {
  let BASE_URL = '';
  if (process.env.NODE_ENV === 'development') {
    //開(kāi)發(fā)環(huán)境 - 根據(jù)請(qǐng)求不同返回不同的BASE_URL
    if (url.includes('/api/')) {
      BASE_URL = ''
    } else if (url.includes('/iatadatabase/')) {
      BASE_URL = ''
    }
  } else {
    // 生產(chǎn)環(huán)境
    if (url.includes('/api/')) {
      BASE_URL = ''
    } else if (url.includes('/iatadatabase/')) {
      BASE_URL = ''
    }
  }
  return BASE_URL
}

export default getBaseUrl;

請(qǐng)求狀態(tài)文件config.js

export const HTTP_STATUS = {
  SUCCESS: 200,
  CREATED: 201,
  ACCEPTED: 202,
  CLIENT_ERROR: 400,
  AUTHENTICATE: 401,
  FORBIDDEN: 403,
  NOT_FOUND: 404,
  SERVER_ERROR: 500,
  BAD_GATEWAY: 502,
  SERVICE_UNAVAILABLE: 503,
  GATEWAY_TIMEOUT: 504
}

叮叮,這樣整體的封裝就完成了

擴(kuò)展

添加分包

[圖片上傳失敗...(image-7e87db-1642501786544)]

app.config.js

export default {
  pages: [
    'pages/login/index',
    'pages/index/index'
  ],
  subPackages: [
    { root: "modules", pages: ["test/index", "detail/index"] }
  ],
  window: {
    backgroundTextStyle: 'light',
    navigationBarBackgroundColor: '#fff',
    navigationBarTitleText: 'WeChat',
    navigationBarTextStyle: 'black'
  }
}

http返回修改

結(jié)果返回從promise修改為現(xiàn)在直接返回結(jié)果

http.js

import Taro from "@tarojs/taro";
import getBaseUrl from "./baseUrl";
import { HTTP_STATUS } from "./config";
import { STORAGE_DATA } from "./constant";
import interceptors from "./interceptors";
import { createNonceSt, MD5withRSA, pageToLogin, signjs } from "./utils";

interceptors.forEach(interceptorItem => Taro.addInterceptor(interceptorItem));

class httpRequest {
  baseOptions(params, method = "GET") {
    let { url, data } = params;
    //添加token 隨機(jī)數(shù) sign
    if (Taro.getStorageSync(STORAGE_DATA.TOKEN))
      data.token = Taro.getStorageSync(STORAGE_DATA.TOKEN);
    if (!data.retrieveIntervalTime) data.retrieveIntervalTime = 60000;
    if (!data.retrieveTime) data.retrieveTime = new Date().getTime();

    data.nonce = createNonceSt();
    data.sign = MD5withRSA(signjs(data));
    const BASE_URL = getBaseUrl(url);
    let contentType = "application/json";
    contentType = params.contentType || contentType;
    const option = {
      url: BASE_URL + url, //地址
      data: data, //傳參
      method: method, //請(qǐng)求方式
      timeout: 50000, // 超時(shí)時(shí)間
      header: {
        "content-type": contentType,
        Authorization: `Bearer ${Taro.getStorageSync(STORAGE_DATA.TOKEN)}`
      }
    };
    // return Taro.request(option);
    if (process.env.NODE_ENV === "development") {
      console.log(
        `${new Date().toLocaleString()}【 M=${option.url} 】P=${JSON.stringify(
          option.data
        )}`
      );
    }
    return Taro.request(option)
      .then(res => {
        console.log("resres", res);
        if (res) {
          if (
            res.code >= HTTP_STATUS.SUCCESS &&
            res.code < HTTP_STATUS.MULTI_SELECT
          ) {
            if (process.env.NODE_ENV === "development") {
              console.log(
                `${new Date().toLocaleString()}【 M=${
                  option.url
                } 】【接口響應(yīng):】`,
                res
              );
            }
            return res;
          } else {
            throw new Error(
              `${res.desc || "網(wǎng)絡(luò)請(qǐng)求錯(cuò)誤,狀態(tài)碼"}(${res.code})`
            );
          }
        } else {
          throw new Error(`數(shù)據(jù)返回異常,請(qǐng)重試`);
        }
      })
      .catch(error => {
        console.log("http error", error);
        Taro.showToast({ title: error.message || "服務(wù)異常", icon: "none" });
        // pageToLogin()
        // return null;
      });
  }

  get(url, data = "") {
    let option = { url, data };
    return this.baseOptions(option);
  }

  post(url, data, contentType) {
    let params = { url, data, contentType };
    return this.baseOptions(params, "POST");
  }

  put(url, data = "") {
    let option = { url, data };
    return this.baseOptions(option, "PUT");
  }

  delete(url, data = "") {
    let option = { url, data };
    return this.baseOptions(option, "DELETE");
  }
}

export default new httpRequest();

驗(yàn)簽過(guò)程添加

//公共驗(yàn)簽

1 公共驗(yàn)簽方法是用于生成訪(fǎng)問(wèn)api的sign簽的一個(gè)公共方法,生成的sign將用于api接口有效性與權(quán)限的驗(yàn)證,以保證接口互通的安全性。

2 簽名算法:

簽名生成的通用步驟如下:

第一步,設(shè)所有發(fā)送或者接收到的數(shù)據(jù)為集合M(不包含sign),將集合M內(nèi)非空參數(shù)值的參數(shù)按照參數(shù)名ASCII碼從小到大排序(字典序),使用URL鍵值對(duì)的格式(即key1=value1&key2=value2…)拼接成字符串stringA。

特別注意以下重要規(guī)則:

1.◆ 參數(shù)名ASCII碼從小到大排序(字典序);

2.◆ 如果參數(shù)的值為空不參與簽名;

3.◆ 參數(shù)名區(qū)分大小寫(xiě);

4.◆ 驗(yàn)證調(diào)用返回或主動(dòng)通知簽名時(shí),傳送的sign參數(shù)不參與簽名,將生成的簽名與該sign值作校驗(yàn)。

5.◆ 接口可能增加字段,驗(yàn)證簽名時(shí)必須支持增加的擴(kuò)展字段

第二步,在stringA最后拼接上apikey得到stringSignTemp字符串,并對(duì)stringSignTemp進(jìn)行MD5運(yùn)算,再將得到的字符串所有字符轉(zhuǎn)換為大寫(xiě),得到signMD5,對(duì)signMD5值進(jìn)行RSA運(yùn)算得到sign。

舉例:

假設(shè)傳送的參數(shù)如下:

appid: wxd930ea5d5a258f4f

mch_id: 10000100

device_info: 1000

body: test

nonce: ibuaiVcKdpRxkhJA

第一步:對(duì)參數(shù)按照key=value的格式,并按照參數(shù)名ASCII字典序排序如下:

stringA="appid=wxd930ea5d5a258f4f&body=test&device_info=1000&mch_id=10000100&nonce=ibuaiVcKdpRxkhJA";

第二步:拼接API密鑰:

MD5簽名方式:

stringSignTemp=stringA+"&key=192006250b4c09247ec02edce69f6a2d" //注:key為用戶(hù)的userCode

signMD5=MD5(stringSignTemp).toUpperCase()="9A0A8659F005D6984697E2CA0A9CF3B7" //注:MD5簽名方式

RSA簽名方式:

sign=RSA(signMD5,appSecret)="6A9AE1657590FD6257D693A078E1C3E4BB6BA4DC30B23E0EE2496E54170DACD6"

注:

1 RSA簽名方式中的加密算法為RSA,簽名算法為MD5withRSA

2生成隨機(jī)數(shù)算法

API接口協(xié)議中包含字段nonce,主要保證簽名不可預(yù)測(cè)。我們推薦生成隨機(jī)數(shù)算法如下:調(diào)用隨機(jī)數(shù)函數(shù)生成,將得到的值轉(zhuǎn)換為字符串。

2.1.3字段介紹:

nonce 隨機(jī)數(shù)

key 為用戶(hù)的userCode

utils.js中的MD5withRSAsignjs、sortObjcreateNonceSt為封裝的驗(yàn)簽加密算法(已驗(yàn)證可以使用)

import Taro from "@tarojs/taro";
import md5 from "./md5js";
import { STORAGE_DATA } from "./constant";
import { hextob64, KEYUTIL, KJUR, RSAKey } from "jsrsasign";
/**
 * @description 獲取當(dāng)前頁(yè)url
 */
export const getCurrentPageUrl = () => {
  let pages = Taro.getCurrentPages();
  let currentPage = pages[pages.length - 1];
  let url = currentPage.route;
  return url;
};

export const pageToLogin = () => {
  let path = getCurrentPageUrl();
  Taro.clearStorageSync();
  if (!path.includes("login")) {
    Taro.reLaunch({
      url: "/pages/login/index"
    });
  }
};

/** 對(duì)象轉(zhuǎn)url參數(shù) */
export const stringify = params => {
  const obj = typeof params === "object" && params !== null ? params : {};
  const isEmpty = v => v === "" || v === null || v === undefined;
  return Object.keys(obj)
    .filter(k => !isEmpty(obj[k]))
    .map(key => `${key}=${encodeURIComponent(obj[key])}`)
    .join("&");
};

export const repeat = (str = "0", times) => new Array(times + 1).join(str);
// 時(shí)間前面 +0
export const pad = (num, maxLength = 2) =>
  repeat("0", maxLength - num.toString().length) + num;
/** 時(shí)間格式的轉(zhuǎn)換 */
export const formatTime = time =>
  `${pad(time.getHours())}:${pad(time.getMinutes())}:${pad(
    time.getSeconds()
  )}.${pad(time.getMilliseconds(), 3)}`;

export var globalData = {}; // 全局公共變量

// 使用es6的padStart()方法來(lái)補(bǔ)0
export const getYMDHMS = timestamp => {
  let time = timestamp ? new Date(timestamp) : new Date();
  let year = time.getFullYear();
  const month = (time.getMonth() + 1).toString().padStart(2, "0");
  const date = time
    .getDate()
    .toString()
    .padStart(2, "0");
  const hours = time
    .getHours()
    .toString()
    .padStart(2, "0");
  const minute = time
    .getMinutes()
    .toString()
    .padStart(2, "0");
  const second = time
    .getSeconds()
    .toString()
    .padStart(2, "0");

  return (
    year +
    "年" +
    month +
    "月" +
    date +
    "日 " +
    hours +
    "時(shí)" +
    minute +
    "分" +
    second +
    "秒"
  );
};

export function getFileName(filePath) {
  if (!filePath) return null;
  let index = filePath.lastIndexOf("/");
  const name = filePath.substring(index + 1);
  return name;
}

// 使用es6的padStart()方法來(lái)補(bǔ)0
export const getYMDHMS2 = timestamp => {
  let time = timestamp ? new Date(timestamp) : new Date();
  let year = time.getFullYear();
  const month = (time.getMonth() + 1).toString().padStart(2, "0");
  const date = time
    .getDate()
    .toString()
    .padStart(2, "0");
  const hours = time
    .getHours()
    .toString()
    .padStart(2, "0");
  const minute = time
    .getMinutes()
    .toString()
    .padStart(2, "0");
  const second = time
    .getSeconds()
    .toString()
    .padStart(2, "0");

  return (
    year + "-" + month + "-" + date + " " + hours + ":" + minute + ":" + second
  );
};

export function dateStr() {
  let date = new Date();
  if (date.getHours() >= 0 && date.getHours() < 12) {
    return "上午好";
  } else if (date.getHours() >= 12 && date.getHours() < 18) {
    return "下午好";
  } else {
    return "晚上好";
  }
}

/**
 * 校驗(yàn)手機(jī)號(hào)是否正確
 * @param phone 手機(jī)號(hào)
 */

export const verifyPhone = phone => {
  const reg = /^1[0-9]{10}$/;
  const _phone = phone.toString().trim();
  let toastStr =
    _phone === ""
      ? "手機(jī)號(hào)不能為空~"
      : !reg.test(_phone) && "請(qǐng)輸入正確手機(jī)號(hào)~";
  return {
    errMsg: toastStr,
    done: !toastStr,
    value: _phone
  };
};

export const verifyStr = (str, text) => {
  const _str = str.toString().trim();
  const toastStr = _str.length ? false : `請(qǐng)?zhí)顚?xiě)${text}~`;
  return {
    errMsg: toastStr,
    done: !toastStr,
    value: _str
  };
};

// 截取字符串

export const sliceStr = (str, sliceLen) => {
  if (!str) {
    return "";
  }
  let realLength = 0;
  const len = str.length;
  let charCode = -1;
  for (var i = 0; i < len; i++) {
    charCode = str.charCodeAt(i);
    if (charCode >= 0 && charCode <= 128) {
      realLength += 1;
    } else {
      realLength += 2;
    }
    if (realLength > sliceLen) {
      return `${str.slice(0, i)}...`;
    }
  }

  return str;
};

/**
 * JSON 克隆
 * @param {Object | Json} jsonObj json對(duì)象
 * @return {Object | Json} 新的json對(duì)象
 */
export function objClone(jsonObj) {
  var buf;
  if (jsonObj instanceof Array) {
    buf = [];
    var i = jsonObj.length;
    while (i--) {
      buf[i] = objClone(jsonObj[i]);
    }
    return buf;
  } else if (jsonObj instanceof Object) {
    buf = {};
    for (var k in jsonObj) {
      buf[k] = objClone(jsonObj[k]);
    }
    return buf;
  } else {
    return jsonObj;
  }
}

export function MD5withRSA(signMd5) {
  if (!Taro.getStorageSync(STORAGE_DATA.PRIVATEKEY)) return;
  const pem = `-----BEGIN PRIVATE KEY-----${Taro.getStorageSync(
    STORAGE_DATA.PRIVATEKEY
  )}-----END PRIVATE KEY-----`;

  let key = KEYUTIL.getKey(pem);
  // 創(chuàng)建 Signature 對(duì)象
  let signature = new KJUR.crypto.Signature({ alg: "MD5withRSA" });
  // 傳入key實(shí)例, 初始化signature實(shí)例
  signature.init(key);
  // 傳入待簽明文
  signature.updateString(signMd5);
  const signInfo = signature.sign();
  const sign = hextob64(signInfo);
  console.log("signature:", signInfo, sign);
  // 簽名, 得到16進(jìn)制字符結(jié)果
  return sign;
}

// 支付md5加密獲取sign
export function signjs(jsonobj) {
  var signstr = obj2str(jsonobj);
  if (Taro.getStorageSync(STORAGE_DATA.USERID)) {
    signstr = signstr + "&key=" + Taro.getStorageSync(STORAGE_DATA.USERID);
  }
  var sign = md5(signstr); //驗(yàn)證調(diào)用返回或微信主動(dòng)通知簽名時(shí),傳送的sign參數(shù)不參與簽名,將生成的簽名與該sign值作校驗(yàn)。
  console.log("signstrkey:", signstr, signstr.length, sign, sign.toUpperCase());
  return sign.toUpperCase();
}

export function sortObj(obj) {
  if (obj instanceof Array) {
    let newArr = [];
    newArr = obj.map((item, index) => {
      return sortObj(item);
    });
    return newArr;
  } else if (obj instanceof Object) {
    let keys = Object.keys(obj);
    if (!(keys && keys.length > 0)) return null;
    keys = keys.sort(); //參數(shù)名ASCII碼從小到大排序(字典序);
    let newObj = {};
    keys.forEach(function(key) {
      if (obj[key] !== "" && obj[key] !== undefined && obj[key] !== null) {
        //如果參數(shù)的值為空不參與簽名;
        newObj[key] = sortObj(obj[key]); //參數(shù)名區(qū)分大小寫(xiě);
      }
    });
    return newObj;
  } else {
    return obj;
  }
}

//object轉(zhuǎn)string,用于簽名計(jì)算
export function obj2str(args) {
  if (!args) return;
  let newArgs = sortObj(args);
  console.log("sortObj\n", args, "\n", newArgs);
  let string = "";
  for (let k in newArgs) {
    string +=
      "&" +
      k +
      "=" +
      (typeof newArgs[k] == "object" ? JSON.stringify(newArgs[k]) : newArgs[k]);
  }
  string = string.substr(1);
  return string;
}

//隨機(jī)函數(shù)的產(chǎn)生:
export function createNonceSt() {
  return Math.random()
    .toString(36)
    .substr(2, 15); //隨機(jī)小數(shù),轉(zhuǎn)換36進(jìn)制,去掉0.,保留余下部分
}

//時(shí)間戳產(chǎn)生的函數(shù), 當(dāng)前時(shí)間以證書(shū)表達(dá),精確到秒的字符串
export function createTimeStamp() {
  return parseInt(new Date().getTime() / 1000) + "";
}

export function sort_ASCII(obj) {
  var arr = new Array();
  var num = 0;
  for (var i in obj) {
    arr[num] = i;
    num++;
  }
  var sortArr = arr.sort();
  var sortObj = {};
  for (var i in sortArr) {
    sortObj[sortArr[i]] = obj[sortArr[i]];
  }
  return sortObj;
}

/** 檢查更新 */
export function checkForUpdate() {
  if (Taro.canIUse("getUpdateManager")) {
    const updateManager = Taro.getUpdateManager();
    updateManager.onCheckForUpdate(res => {
      // 請(qǐng)求完新版本信息的回調(diào)
      if (res.hasUpdate) {
        updateManager.onUpdateReady(() => {
          Taro.showModal({
            title: "更新提示",
            content: "新版本已經(jīng)準(zhǔn)備好,是否重啟應(yīng)用?",
            showCancel: false,
            confirmColor: "#40A3FF",
            success: res => {
              if (res.confirm) {
                // 新的版本已經(jīng)下載好,調(diào)用 applyUpdate 應(yīng)用新版本并重啟
                updateManager.applyUpdate();
              }
            }
          });
        });

        updateManager.onUpdateFailed(() => {
          // 新版本下載失敗
          Taro.showModal({
            title: "更新提示",
            content: "新版本已經(jīng)上線(xiàn),請(qǐng)刪除當(dāng)前小程序,重新掃碼進(jìn)入",
            confirmColor: "#40A3FF",
            showCancel: false
          });
        });
      }
    });
  }
}
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容