微信小程序及h5豺瘤,基于taro,zoro最佳實踐探索

這段時間一直忙于公司業(yè)務中听诸,不可自拔坐求,好在通過零零星星的點滴時間,慢慢的還是完成了腳手架搭建晌梨。微信小程序發(fā)展到現(xiàn)在桥嗤,已經(jīng)不再像以前只是簡簡單單的應用,業(yè)務愈發(fā)的臃腫了起來仔蝌,同時也催生出了許多框架泛领,mpvue,wepy以及后起之秀taro等敛惊。

搭建這次腳手架的目的主要是為了滿足后期小程序快速開發(fā)的需求渊鞋,首先看看該腳手架搭建的簡單的todo演示應用效果


打包生成的微信小程序演示.gif

打包生成的h5應用演示.gif

最初選擇taro,主要的原因是習慣于react開發(fā)方式,在taro還沒發(fā)布正式版之前锡宋,上一個項目選擇了wepy作為開發(fā)框架儡湾,深陷苦擾,我們不得不游走切換于wepy語法及原生小程序組件語法之間

特性

  • 簡化redux的引入和配置执俩,只需簡單幾步即可快速開發(fā)
  • 簡易的環(huán)境配置徐钠,支持配置多環(huán)境開發(fā)
  • 對于業(yè)務錯誤進行了全局捕獲,即可統(tǒng)一提示役首,又可定制性處理
  • 引入資源自動上傳阿里云oss服務器尝丐,并自動替換成最終服務器路徑
  • 封裝request,支持restful api

快速開始

我們使用yarn工具代替npm進行依賴管理衡奥,沒有安裝yarn的摊崭,請先安裝,實在不想安裝杰赛,可以用npm代替

綁定oss配置信息

首先我們克隆腳手架到本地服務器

$ git clone git@github.com:FaureWu/ztaro.git

安裝依賴包

$ cd ./ztaro
$ yarn # 如果沒有安裝yarn 則可以使用npm install

接下來我們需要配置阿里云oss服務器呢簸,打開文件./ztaro/config/config.js

module.exports = {
  // 阿里云oss插件配置
  oss: {
    dev: {
      accessKeyId: '************',
      accessKeySecret: '***************',
      endpoint: 'https://************.aliyuncs.com',
      region: '*************',
      bucket: '*********',
    },
    prod: {
      accessKeyId: '************',
      accessKeySecret: '***************',
      endpoint: 'https://************.aliyuncs.com',
      region: '*************',
      bucket: '*********',
    },
    path: 'src/assets/',
    prefix: '@oss',
    formats: ['png', 'jpeg', 'jpg', 'svg'],
  },
}

可以看到oss配置項,該配置項支持區(qū)分編譯環(huán)境BUILD_ENV乏屯,dev為開發(fā)環(huán)境下的配置根时,prod為線上環(huán)境的配置,要是沒有區(qū)分辰晕,那就都配置成一樣的嘛蛤迎,其中accessKeyId,accessKeySecret含友,endpoint替裆,region,bucket都是阿里云oss基本配置窘问,這里就不多說了辆童,說一下其他參數(shù)吧

  • path 這個路徑用于指定需要上傳到阿里云oss資源的搜索路徑,這個路徑下的資源并不會所有的全部都上傳到阿里云惠赫,只會上傳在代碼中使用的并且以prefix開頭的資源
  • prefix 需要上傳到阿里云oss的前綴把鉴,也類似path的路徑別名
  • formats 需要上傳資源格式

以下代碼僅用于展示如何使用,需要把資源放入上面配置的path路徑下儿咱,無法使用require, import導入庭砍,無法在tabbar中配置

<Image src="@oss/logo.jpeg" /> // 可以這樣用

或者

 const activeHomeIcon = '@oss/home-active.png' // 或者這樣用

或者在樣式文件中

.app {
  background: url('@oss/logo.jpeg') // 還可以這樣用
}

又或者在json文件中

{
  "logo": "@oss/logo.jpeg" // 又或者這樣用
}

讓微信小程序跑起來

執(zhí)行如下命令,該命令會做三件事

  • 編譯taro語法為微信小程序語法混埠,并啟動監(jiān)聽文件修改
  • 啟動本地mock服務器
  • 啟動gulp任務怠缸,上傳圖片資源,并監(jiān)聽文件修改
$ yarn mock:weapp

等待命令執(zhí)行完成钳宪,會在根目錄下生成dist目錄揭北,打開微信開發(fā)者工具概耻,選擇編譯后dist預覽最終效果

編寫todo應用

當我們準備開始編寫一個功能前,我們希望能數(shù)據(jù)驅(qū)動開發(fā)罐呼,所以首先我們編寫模擬api請求,該腳手架主要是采用express搭建一個簡易的node api服務器侦高,通過faker進行模擬數(shù)據(jù)嫉柴,如果習慣其他生成模擬數(shù)據(jù)的庫,可以替換faker

編寫獲取todo列表的接口奉呛,新建文件ztaro/mock/todos.js

const faker = require('faker')

function createTodos(number) {
  const todos = []
  for (let i = 0; i < number; i += 1) {
    todos.push({
      id: faker.random.uuid(),
      text: faker.random.words(10),
    })
  }

  return todos
}

let todos = createTodos(faker.random.number({ min: 3, max: 6 }))

function getTodos(req, res) {
  res.status(200).json({
    code: 'success',
    message: '獲取待辦列表成功',
    data: todos,
  })
}

module.exports = {
  'GET /v1/todos': getTodos,
}

編寫getTodos的request請求计螺,新建/ztaro/src/requests/todos.js

import request from '../utils/request'

export function getTodos() {
  return request({
    url: '/v1/todos',
  })
}

編寫用于todos model,在ztaro/src/models/todos.js

import { getTodos } from '../requests/todos'

export default {
  namespace: 'todos',
  state: {
    lists: [],
  },
  // 這里的配置用于擴展model瞧壮,model之前共用邏輯
  // common mixins定義于ztaro/src/mixins/common.js
  // 主要提供共用的update action
  mixins: ['common'],
  effects: {
    async getTodos(action, { put }) {
      const { data } = await getTodos()
      // 這里的update是由于上面引入了common mixins
      // 如果沒有引入打開下方的reducers注釋
      put({ type: 'update', payload: { lists: data } })
    },
  },
  // reducers: {
  //  update({ payload }, state) {
  //    return { ...state, ...payload }
  //  },
  // },
  },

將todos model注入到應用中登馒,引入到ztaro/src/models/index.js

import todos from './todos'

export default [todos]

該文件會被引入到到app.js中

數(shù)據(jù)準備已經(jīng)完成,我們可以開始編寫界面咆槽,ztaro/src/pages/todos/*

import Taro, { Component } from '@tarojs/taro'
import { View } from '@tarojs/components'
import { connect } from '@tarojs/redux'
import { dispatcher } from '@opcjs/zoro'

import ComponentSpin from '../../components/spin/spin'

import './todos.scss'

// 從redux中綁定數(shù)據(jù)到界面
@connect(({ todos }) => ({
  todos: todos.lists,
}))
class PageTodos extends Component {
  config = {
    navigationBarTitleText: '待辦事項',
  }

  state = {
    loading: false,
  }

  componentWillMount() {
    this.showLoading()
    dispatcher.todos
      .getTodos()
      // 獲取成功之后執(zhí)行.then
      .then(this.hideLoading)
      // 獲取失敗之后執(zhí)行.catch
      .catch(this.hideLoading)
  }

  showLoading = () => this.setState({ loading: true })

  hideLoading = () => this.setState({ loading: false })

  render() {
    const { todos } = this.props
    const { value, loading } = this.state

    return (
      <View className="todos">
        <ComponentSpin loading={loading} />
        <View className="logo" />
        {todos.map(todo => (
          <View className="todo" key={todo.id}>
            <Text>{todo.text}</Text>
          </View>
        ))}
      </View>
    )
  }
}

export default PageTodos

最后我們需要編寫我們的樣式

.todos {
  position: relative;
  counter-reset: count;

  .logo {
    display: block;
    height: 160px;
    // 這里以@oss前墜開頭陈轿,因此編譯時會被上傳至阿里云oss,并替換成最終路徑
    background-image: url("@oss/logo.jpeg");
    background-size: auto 160px;
    background-repeat: no-repeat;
    background-origin: center;
  }

  .todo {
    font-size: 28px;
    word-break: break-all;
    counter-increment: count;
    padding: 10px;
    display: flex;
    flex-direction: row;
    justify-content: flex-start;
    align-items: flex-start;

    &::before {
      content: counter(count);
      display: inline-block;
      border: 2px solid #e9e9e9;
      padding: 0 10px;
      margin: 0 10px 0 0;
      border-radius: 10px;
    }
  }
}

全局錯誤提示

在zoro框架中秦忿,可以注冊一個全局錯誤函數(shù)onError麦射,該函數(shù)注冊于ztaro/src/app.js

import zoro from '@opcjs/zoro'

const app = zoro({
  onError(error) {
    if (error.message) {
      Taro.showToast({
        icon: 'none',
        title: error.message,
        duration: 2000,
      })
    }
  },
})

zoro框架會對于每一個effect外層做了try/catch,捕獲在執(zhí)行effect過程中拋出的一切錯誤灯谣,并回調(diào)到onError函數(shù)里

那我們?nèi)绾尾东@異步請求的錯誤呢潜秋,我們可以移步ztaro/src/utils/request.js

export default function request(options) {
  const { url } = options
  return Taro.request(
    resolveParams({
      ...options,
      url: `${CONFIG.SERVER}${url}`,
      mode: 'cors',
      header: {
        'content-type': 'application/json',
        ...options.header,
      },
    }),
  )
  .then(checkHttpStatus)
  .then(checkSuccess)
  .catch(throwError)
}

封裝的request函數(shù)中有checkHttpStatus,checkSuccess兩個函數(shù)胎许,我們分別看下它們做了什么

function checkHttpStatus(response) {
  // 當http狀態(tài)在200到300之間時峻呛,說明請求是成功的
  // 我們只需返回響應的數(shù)據(jù)即可
  if (response.statusCode >= 200 && response.statusCode < 300) {
    return response.data
  }
  
  // 當狀態(tài)出現(xiàn)錯誤時,我們需要拋出相關信息
  // 這樣錯誤被一層層往上拋出辜窑,最終被zoro捕獲钩述,回調(diào)onError函數(shù)
  const message =
    HTTP_ERROR[response.statusCode] || `ERROR CODE: ${response.statusCode}`
  const error = new Error(message)
  error.response = response
  throw error
}

function checkSuccess(data) {
  // 當數(shù)據(jù)是個字符串,或者是ArrayBuffer時穆碎,我們認為業(yè)務是成功的
  // 返回數(shù)據(jù)即可
  if (typeof data === 'string' && data instanceof ArrayBuffer) {
    return data
  }

  // 當業(yè)務響應數(shù)據(jù)中的code值返回SUCCESS時切距,我們認為業(yè)務是成功的
  // 這里主要根據(jù)與后端約定好的格式,你可以根據(jù)實際情況進行更改
  if (
    typeof data.code === 'string' &&
    data.code.toLocaleUpperCase() === 'SUCCESS'
  ) {
    return data
  }
  
  // 當業(yè)務出現(xiàn)錯誤時惨远,我們依舊需要獲取后臺拋出的錯誤谜悟,
  // 像上一層拋出錯誤,最終被zoro捕獲北秽,回調(diào)onError
  const error = new Error(data.message)
  error.data = data
  throw error
}

這樣處理過后葡幸,當后臺接口報錯,或者業(yè)務錯誤時贺氓,就會看到彈出toast錯誤提示了蔚叨,無需額外的處理

那當我們想要屏蔽某些不那么重要的接口,錯誤提示,我們該怎么辦呢蔑水?就那getTodos來舉例邢锯,我們只需修改它

async getTodos(action, { put }) {
  try {
    const { data } = await getTodos()
    put({ type: 'update', payload: { lists: data } })
  } catch (error) {
    // 這里僅僅是為了可以知道該接口是否錯誤
    return { isError: true, error }
  }
}

這樣即使是getTodos接口拋出錯誤也不會觸發(fā)全局錯誤提示了

接下來我們可以自定義該接口的錯誤邏輯了

dispatcher.todos.getTodos().then((data = {}) => {
  if (data.isError) {
    // 執(zhí)行一些相關的錯誤
  }
})

假如我們想要在dispatcher.todos.getTodos()的.then函數(shù)中獲取到某些數(shù)據(jù),我們又該如何呢搀别?依舊那getTodos舉例

async getTodos(action, { put }) {
  const { data } = await getTodos()
  put({ type: 'update', payload: { lists: data } })
  return data
}

然后我們在使用的時候

dispatcher.todos.getTodos().then(data => console.log(data))

與服務器進行接口聯(lián)調(diào)

在進行接口聯(lián)調(diào)之前丹擎,我們首先需要配置開發(fā)環(huán)境下的api地址,打開./ztaro/config/config.js

module.exports = {
  server: {
    // 修改下面這一行為你的開發(fā)環(huán)境下的api服務器
    dev: 'https://devapiserver',
  },
}

配置完成后執(zhí)行如下命令

yarn dev:weapp

這個所有的api便會指向開發(fā)環(huán)境下的api服務器地址了

打包測試包

執(zhí)行如下命令即可

yarn build:weapp-dev

打包線上包

首先配置生產(chǎn)環(huán)境下的api地址歇父,打開./ztaro/config/config.js

module.exports = {
  server: {
    // 修改下面這一行為你的生產(chǎn)環(huán)境下的api服務器
    prod: 'https://devapiserver',
  },
}

配置完成后執(zhí)行

yarn build:weapp

以上教程僅列出了微信小程序端蒂培,h5端也基本是一致的,只需執(zhí)行的命令中榜苫,將weapp替換成h5即可

其他更詳細的使用方式护戳,請查看對應github倉庫

歡迎star,歡迎加我咨詢相關問題

最后編輯于
?著作權歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末垂睬,一起剝皮案震驚了整個濱河市媳荒,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌驹饺,老刑警劉巖肺樟,帶你破解...
    沈念sama閱讀 216,470評論 6 501
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異逻淌,居然都是意外死亡么伯,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,393評論 3 392
  • 文/潘曉璐 我一進店門卡儒,熙熙樓的掌柜王于貴愁眉苦臉地迎上來田柔,“玉大人,你說我怎么就攤上這事骨望∮脖” “怎么了?”我有些...
    開封第一講書人閱讀 162,577評論 0 353
  • 文/不壞的土叔 我叫張陵擎鸠,是天一觀的道長缀磕。 經(jīng)常有香客問我,道長劣光,這世上最難降的妖魔是什么袜蚕? 我笑而不...
    開封第一講書人閱讀 58,176評論 1 292
  • 正文 為了忘掉前任,我火速辦了婚禮绢涡,結果婚禮上牲剃,老公的妹妹穿的比我還像新娘。我一直安慰自己雄可,他們只是感情好凿傅,可當我...
    茶點故事閱讀 67,189評論 6 388
  • 文/花漫 我一把揭開白布缠犀。 她就那樣靜靜地躺著,像睡著了一般聪舒。 火紅的嫁衣襯著肌膚如雪辨液。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,155評論 1 299
  • 那天箱残,我揣著相機與錄音滔迈,去河邊找鬼。 笑死疚宇,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的赏殃。 我是一名探鬼主播敷待,決...
    沈念sama閱讀 40,041評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼仁热!你這毒婦竟也來了榜揖?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 38,903評論 0 274
  • 序言:老撾萬榮一對情侶失蹤抗蠢,失蹤者是張志新(化名)和其女友劉穎举哟,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體迅矛,經(jīng)...
    沈念sama閱讀 45,319評論 1 310
  • 正文 獨居荒郊野嶺守林人離奇死亡妨猩,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,539評論 2 332
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了秽褒。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片壶硅。...
    茶點故事閱讀 39,703評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖销斟,靈堂內(nèi)的尸體忽然破棺而出庐椒,到底是詐尸還是另有隱情,我是刑警寧澤蚂踊,帶...
    沈念sama閱讀 35,417評論 5 343
  • 正文 年R本政府宣布约谈,位于F島的核電站,受9級特大地震影響犁钟,放射性物質(zhì)發(fā)生泄漏遇骑。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,013評論 3 325
  • 文/蒙蒙 一魁索、第九天 我趴在偏房一處隱蔽的房頂上張望尉共。 院中可真熱鬧,春花似錦捧存、人聲如沸粪躬。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,664評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽镰官。三九已至提前,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間泳唠,已是汗流浹背狈网。 一陣腳步聲響...
    開封第一講書人閱讀 32,818評論 1 269
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留笨腥,地道東北人拓哺。 一個月前我還...
    沈念sama閱讀 47,711評論 2 368
  • 正文 我出身青樓,卻偏偏與公主長得像脖母,于是被迫代替她去往敵國和親士鸥。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 44,601評論 2 353

推薦閱讀更多精彩內(nèi)容

  • Spring Cloud為開發(fā)人員提供了快速構建分布式系統(tǒng)中一些常見模式的工具(例如配置管理谆级,服務發(fā)現(xiàn)烤礁,斷路器,智...
    卡卡羅2017閱讀 134,651評論 18 139
  • 相信做過微信小程序的都知道肥照,官方給出的微信web開發(fā)工具上根本就無法加載node_modules包脚仔,即使可以加載,...
    蕭玄辭閱讀 1,340評論 0 2
  • 許村漫記~001(2017.7.15) 出發(fā) 許村漫記~002(2017.7.15) 到了 許村漫記~003(20...
    王軼瓊閱讀 1,093評論 0 1
  • 深夜 憧憬著 我愛的你 每一次遇見 想輕撫你臉頰 撥弄你秀發(fā) 觸摸你的唇 傻傻的我不敢 驚醒夢中你 終有一天 你走...
    草中藏朱閱讀 378評論 7 13
  • P199–214 1. 把獎勵當作學習的誘餌提出來舆绎,是一種成人要求兒童以成績回報自己的行賄手段鲤脏,他讓孩子對學習不再...
    冰淇淋cathy閱讀 146評論 0 0