【Taro開發】四月芳菲,Taro觀賞指南

語言: CN / TW / HK

背景

最近接到多端開發,因為老項目使用的React,考慮到遷移成本,選擇了Taro,遷移成本相對較低,且上手較快。

Taro和uni-app

我做了一下調研,目前市面上優秀且成熟的開源框架有很多。其中,Taro和uni-app作為兩大“豪門”框架,優秀之處各有千秋,為我提供了更多的選擇項。

關於它們的對比可以參看下面這篇掘金好文:

Taro

綜合考量,尤其是前面提到的,遷移成本,我最後選擇了Taro。下面主要介紹Taro的使用以及遷移中的功能總結。

Taro的官方文檔內容很全面,基本的操作跟着官方文檔即可完成,官方文檔地址

我的項目目前只有兩個端的業務場景,分別是微信小程序和H5,所以技術探索也主要針對這兩個端,文章也主要是這兩個端使用總結。

新建項目

CLI 工具安裝

```js

使用 npm 安裝 CLI

$ npm install -g @tarojs/cli

OR 使用 yarn 安裝 CLI

$ yarn global add @tarojs/cli

OR 安裝了 cnpm,使用 cnpm 安裝 CLI

$ cnpm install -g @tarojs/cli ```

項目初始化

使用命令創建模板項目

$ taro init myApp

npm 5.2+ 也可在不全局安裝的情況下使用 npx 創建模板項目

$ npx @tarojs/cli init myApp

安裝依賴

```

進入項目根目錄

$ cd myApp

使用 yarn 安裝依賴

$ yarn

OR 使用 cnpm 安裝依賴

$ cnpm install

OR 使用 npm 安裝依賴

$ npm install ```

安裝完成之後,文件結構已經生成如下圖:

編譯命令

``` // 微信小程序

yarn

$ yarn dev:weapp $ yarn build:weapp

npm script

$ npm run dev:weapp $ npm run build:weapp

// H5

yarn

$ yarn dev:h5 $ yarn build:h5

npm script

$ npm run dev:h5 $ npm run build:h5 ```

項目遷移之React框架版

選擇框架

因為我平時使用React框架進行開發,所以遷移的時候也直接選擇了React框架。這個選擇是在項目初始化的時候選擇的,如下圖:

項目遷移

直接把文件拷貝過來,然後進行調整,主要調整的內容有以下幾個部分

UI框架的調整

原來的項目使用的是antd-mobile,遷移之後改成了@antmjs/vantui,部分組件名以及組件的用法略有不同。

比如下面的頁

  • antd-mobile中的List組件在@antmjs/vantui是沒有的,所以需要重寫這部分代碼;
  • Button組件兩個UI都有,但是裏面的屬性存在差異,針對這部分差異進行修改即可;

``` // import { List, Button } from 'antd-mobile'; import { Button } from '@antmjs/vantui';

// antd-mobile的List組件使用 const listContent = content => { return (

{content.list.map(item => { return (
{item.name}
); })}
); };

// @antmjs/vantui對List組件的改造 const listContent = content => { return ( {content.list.map(item => { return ( {item.name} {item.btnName ? btnContent(item) : null} ); })} ); };

// antd-mobile的Button組件使用

// antd-mobile的Button組件使用 ```


頁面跳轉方法

原生H5的跳轉使用的是History對象提供的push或者replace方法,在Taro裏使用Taro提供的路由API,因為小程序中tabBar中的頁面和其他頁面的跳轉方法不一樣,這個區別Taro也做了區分,為此我寫了一個公共方法做跳轉的統一處理。

/** * 跳轉處理 * @param {string} path app.config.js中的完整地址 例如/pages/home/index */ commonNavigateTo(path) { /** @name 底導航路由列表 */ const switchList = ['/pages/home/index']; if (switchList.includes(path)) { Taro.switchTab({ url: path, }); } else { Taro.navigateTo({ url: path, }); } }

HTML標籤

Taro v3.3以前是不支持使用HTML標籤的,使用的是Taro提供的View、Text等標籤,這些在Taro的組件庫中有詳細介紹。

``` import React, { Component } from 'react' import { View, Text } from '@tarojs/components'

export default class C extends Component { render () { return ( c component ) } } ```

Taro v3.3+ 開始支持使用HTML標籤,需要進行插件配置。

配置插件

1.首先下載安裝插件 @tarojs/plugin-html

yarn add @tarojs/plugin-html

2.然後在項目配置中添加使用插件

// config/index.js config = { // ... plugins: ['@tarojs/plugin-html'] }

注:

  • 如果遇到不支持的標籤可以使用Taro提供的組件,詳見Taro組件庫

項目遷移之原生小程序

後面有規劃把原生小程序項目也使用Taro開發成多端,但是目前還沒有實際應用,待我實際應用之後,再進行更新,我預測會遇到一些有趣的問題。

開發“指南針”

開發過程中難免會遇到各種問題,不過它也側面成為了我的“試金石”,我把遇到的問題、解決方案,詳細的列出來,供jym參考,有些解決方案可能不是最優,歡迎大佬提供更優的方案。

路由跳轉路徑問題

Taro提供的路由跳轉方法基本和小程序一致,可以參看文檔

這裏着重強調一下跳轉的url的完整性,即url要以右斜線開始,否則或被當做相對路由處理。

錯誤示例

Taro.navigateTo({ url: 'pages/order/index', });

報錯如下

errMsg: "navigateTo:fail page "pages/order/orderStatement/pages/order/index" is not found"

正確示例

Taro.navigateTo({ url: '/pages/order/index', });

小程序文件過大的處理方法

1.根據提示開啟壓縮

Tips: 預覽模式生成的文件較大,設置 NODE_ENV 為 production 可以開啟壓縮。 Example: $ NODE_ENV=production taro build --type weapp --watch

2.分包

分包限制如下,官方文檔

  • 整個小程序所有分包大小不超過 20M
  • 單個分包/主包大小不能超過 2M

因為我們的項目不是很大,所以並沒有實際應用這種方案,但是我再掘金上找了幾個不錯的參考文章:

小程序分包(Taro分包案例)

京東購物小程序 | Taro3 項目分包實踐

3.vendors.js過大的原因

vendors.js文件中包含了node_modules 除 Taro 外的公共依賴,可能會因為某些原因導致它體積過大。

下面主要列一下我的項目中導致vendors.js文件過大的原因

3.1 引入了crypto-js

這個第三方加密庫,會導致一些意外的內容被打包進去(具體是什麼官方也沒有説的特別明白,可能是node的一些依賴之類的),解決方案就是降低crypto-js的版本或者直接把crypto-js-min放進本地(本地83KB)。

Taro.request在H5端不能自定義header的解決方案

因為我的項目某些特殊業務邏輯,所以必須添加自定義header,但是H5端Taro.request不支持自定義header(小程序端支持),所以根據不同端區分request的引入。

/** * @description 異步請求分發 H5和小程序使用的不一樣 */ import $ from './request-weapp'; import $2 from './request-h5'; export function requestFunc() { if (process.env.TARO_ENV === 'weapp') { return $; } else { return $2; } }

老項目遷移時H5端自定義路由

因為老項目有一些已經對外的入口,比如外推鏈接、第三方入口等,所以遷移的時候要進行兼容處理。

1.處理前的頁面路由

處理前的頁面路由如下,Taro框架自動生成的,顯然和老項目的不一致

http://{{domain}}/pages/index/index(browser 模式)

2.自定義頁面路由方案1

方案1 是使用Taro提供的方式,配置h5.router.customRoutes

config/index.js

module.exports = { // ... h5: { // ... router: { customRoutes: { // "頁面路徑": "自定義路由" '/pages/index/index': '/index', '/pages/detail/index': ['/detail'] // 可以通過數組為頁面配置多個自定義路由 } } } }

優點:不用做過多的邏輯。

缺點:1)當需要配置的頁面多的時候容易漏;2)新增頁面如果忘記補充,可能會導致跳轉找不到頁面。

3.自定義頁面路由方案2

自己編寫自定義頁面路由的代碼邏輯

app.js

``` import resetRouter from '@utils/resetRouter';

// 掛載生命週期時,h5端引入路由重定向的處理方法 componentDidMount() { // =>true:只有H5才處理路由 if (process.env.TARO_ENV === 'h5') { resetRouter.resetRouter(); } } ```

utils/resetRouter.js

/** * @description 路由攔截處理 頁面404重定向、頁面非Taro最終的H5路由重定向等 */ import Taro, { Current } from '@tarojs/taro'; /** * 獲取小程序tabBar的pagePath數組對象 * @param {Object} taroAppConfigInit 項目配置項 * @return {Array} 最終得到的pagePath數組 */ const getTabBarPageList = taroAppConfigInit => { const tabBarInit = taroAppConfigInit.tabBar ? taroAppConfigInit.tabBar : {}; const tabBarList = tabBarInit.list ? tabBarInit.list : []; const tabBarPageList = []; if (tabBarList.length !== 0) { tabBarList.forEach(item => { tabBarPageList.push('/' + item.pagePath); }); } return tabBarPageList; }; /** * 獲取全部路由的數組對象 * @param {Object} taroAppConfigInit 項目配置項 * @return {Array} 最終得到的數組數組 */ const getAllPagesList = taroAppConfigInit => { const allPagesListInit = taroAppConfigInit.pages ? taroAppConfigInit.pages : []; let allPagesList = []; allPagesListInit.forEach(item => { allPagesList.push('/' + item); }); return allPagesList; }; /** * 獲取頁面是否是404的布爾值 * @param {Array} allPagesList 全部路由數組 * @param {string} pathname 當前頁面路由 * @return {boolean} 最終得到的布爾值 */ const getNoFoundFlag = (allPagesList, pathname) => { let flag = true; if (allPagesList.includes(pathname)) { flag = false; } return flag; }; /** * 頁面路由處理 如果不包含pages的重組成/pages/pathname/index的格式 * @param {string} pathname 當前頁面路由 * @return {boolean} 重組後的路由 */ const resetPathname = pathname => { let pathnameInit = ''; if (pathname.indexOf('pages') === -1) { pathnameInit = '/pages' + pathname + '/index'; } else { pathnameInit = pathname; } return pathnameInit; }; /** * 跳轉處理 跳轉到tabBar頁面使用switchTab,其他使用navigateTo * @param {string} pathname 當前頁面路由 * @param {string} search 當前頁面路由參數 */ const switchTabOrnavigateTo = (pathname, search) => { // 隱藏配置window.__taroAppConfig(包含app.config.js中所有內容) const taroAppConfigInit = Current.app.config ? Current.app.config : {}; const allPagesList = getAllPagesList(taroAppConfigInit); const tabBarPageList = getTabBarPageList(taroAppConfigInit); const pathnameInit = resetPathname(pathname); console.log(pathnameInit, 'pathnameInit'); //=>true: 如果路由類型是tabBar if (tabBarPageList.includes(pathnameInit)) { return Taro.switchTab({ url: pathnameInit, }); } else { const noFoundFlag = getNoFoundFlag(allPagesList, pathnameInit); const url = noFoundFlag ? '/pages/dispatch/nofound/index' : pathnameInit + search; return Taro.navigateTo({ url: url, }); } }; /** * 路由跳轉攔截處理 */ const resetRouter = () => { // H5先從location獲取路由getCurrentInstance().page值為nullTaro還沒有修復 let { pathname, search } = window.location; switchTabOrnavigateTo(pathname, search); }; export default { resetRouter };

缺點:需要自己寫邏輯,增加了額外的工作量。

優點:一次性處理了所有的頁面路由,不需要再次添加,且增加了404的重定向。

UI框架

我們配合Taro的UI框架最終選擇了有讚的@antmjs/vantui。這個UI框架提供的組件很豐富,常見的功能都覆蓋到了,不過它的api文檔寫的略微簡單,我後面可能寫一篇它的使用總結。

總結

萬事開頭難,但是世上無難事只怕有心人。

開源框架是推動技術發展的寶貴資源,有維護成本在的,所以遇到坑,可以轉換思維,自己做兼容處理,比如某些問題可以通過環境區分做處理,雖然繁瑣了一點,但是幫助解決了問題。