寫在前面
Taro 是一套遵循 React 語法規範的 多端開發 解決方案。現如今市面上端的形態多種多樣,Web、React-Native、微信小程式等各種端大行其道,當業務要求同時在不同的端都要求有所表現的時候,針對不同的端去編寫多套程式碼的成本顯然非常高,這時候只編寫一套程式碼就能夠適配到多端的能力就顯得極為需要。
使用 Taro,我們可以只書寫一套程式碼,再通過 Taro 的編譯工具,將原始碼分別編譯出可以在不同端(微信小程式、H5、React-Native 等)執行的程式碼。
技術棧
React + taro + dva
taro的安裝及使用
安裝 Taro 開發工具 @tarojs/cli
使用 npm 或者 yarn 全域性安裝,或者直接使用npx
$ npm install -g @tarojs/cli
$ yarn global add @tarojs/cli
複製程式碼
使用命令建立模板專案
$ taro init myApp
複製程式碼
進入專案目錄開始開發,可以選擇小程式預覽模式,或者 h5 預覽模式,若使用微信小程式預覽模式,則需要自行下載並開啟微信開發者工具,選擇預覽專案根目錄。
微信小程式編譯預覽模式
# npm script
$ npm run dev:weapp
# 僅限全域性安裝
$ taro build --type weapp --watch
# npx 使用者也可以使用
$ npx taro build --type weapp --watch
複製程式碼
H5 編譯預覽模式
# npm script
$ npm run dev:h5
# 僅限全域性安裝
$ taro build --type h5 --watch
# npx 使用者也可以使用
$ npx taro build --type h5 --watch
複製程式碼
RN 編譯預覽模式
# npm script
$ npm run dev:rn
# 僅限全域性安裝
$ taro build --type rn --watch
# npx 使用者也可以使用
$ npx taro build --type rn --watch
複製程式碼
當然到這一步有個大概的骨架,作為生產開發是不夠的,這時候我們引入dva
$ npm i dva-core dva-loading --save
複製程式碼
新建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;
}
}
複製程式碼
並在入口檔案匯入
import dva from './utils/dva'
const dvaApp = dva.createApp({
initialState: {},
models: models,
});
const store = dvaApp.getStore();
複製程式碼
dva整合好了,下面我們來封裝下request網路請求吧
import Taro from '@tarojs/taro';
import { baseUrl, noConsole } from '../config';
export default (options = { method: 'GET', data: {} }) => {
if (!noConsole) {
console.log(`${new Date().toLocaleString()}【 M=${options.url} 】P=${JSON.stringify(options.data)}`);
}
return Taro.request({
url: baseUrl + options.url,
data: options.data,
headers: {
'Content-Type': 'application/json',
},
method: options.method.toUpperCase(),
}).then((res) => {
const { statusCode, data } = res;
if (statusCode >= 200 && statusCode < 300) {
if (!noConsole) {
console.log(`${new Date().toLocaleString()}【 M=${options.url} 】【介面響應:】`,res.data);
}
if (data.status !== 'ok') {
Taro.showToast({
title: `${res.data.error.message}~` || res.data.error.code,
icon: 'none',
mask: true,
});
}
return data;
} else {
throw new Error(`網路請求錯誤,狀態碼${statusCode}`);
}
})
}
複製程式碼
好了,是應該準備pages頁面的開發了,本人比較喜歡umi的目錄結構
pages // 頁面檔案目錄
└── home
├── index.js // 頁面邏輯
├── index.scss // 頁面樣式
├── model.js // 頁面models
└── service.css // 頁面api
複製程式碼
一個page要生成4個檔案?能否用指令碼幫我們自動生成呢?那來寫一個吧
/**
* pages模版快速生成指令碼,執行命令 npm run tep `檔名`
*/
const fs = require('fs');
const dirName = process.argv[2];
if (!dirName) {
console.log('資料夾名稱不能為空!');
console.log('示例:npm run tep test');
process.exit(0);
}
// 頁面模版
const indexTep = `import Taro, { Component } from '@tarojs/taro';
import { View } from '@tarojs/components';
import { connect } from '@tarojs/redux';
import './index.scss';
@connect(({${dirName}}) => ({
...${dirName},
}))
export default class ${titleCase(dirName)} extends Component {
config = {
navigationBarTitleText: '${dirName}',
};
componentDidMount = () => {
};
render() {
return (
<View className="${dirName}-page">
${dirName}
</View>
)
}
}
`;
// scss檔案模版
const scssTep = `@import "../../styles/mixin";
.${dirName}-page {
@include wh(100%, 100%);
}
`;
// model檔案模版
const modelTep = `import * as ${dirName}Api from './service';
export default {
namespace: '${dirName}',
state: {
},
effects: {
* effectsDemo(_, { call, put }) {
const { status, data } = yield call(${dirName}Api.demo, {});
if (status === 'ok') {
yield put({ type: 'save',
payload: {
topData: data,
} });
}
},
},
reducers: {
save(state, { payload }) {
return { ...state, ...payload };
},
},
};
`;
// service頁面模版
const serviceTep = `import Request from '../../utils/request';
export const demo = (data) => {
return Request({
url: '路徑',
method: 'POST',
data,
});
};
`;
fs.mkdirSync(`./src/pages/${dirName}`); // mkdir $1
process.chdir(`./src/pages/${dirName}`); // cd $1
fs.writeFileSync('index.js', indexTep);
fs.writeFileSync('index.scss', scssTep);
fs.writeFileSync('model.js', modelTep);
fs.writeFileSync('service.js', serviceTep);
console.log(`模版${dirName}已建立,請手動增加models`);
function titleCase(str) {
const array = str.toLowerCase().split(' ');
for (let i = 0; i < array.length; i++) {
array[i] = array[i][0].toUpperCase() + array[i].substring(1, array[i].length);
}
const string = array.join(' ');
return string;
}
process.exit(0);
複製程式碼
現在是時候進行愉快的開發了。。。
目錄結構
├── .temp // H5編譯結果目錄
├── .rn_temp // RN編譯結果目錄
├── dist // 小程式編譯結果目錄
├── config // Taro配置目錄
│ ├── dev.js // 開發時配置
│ ├── index.js // 預設配置
│ └── prod.js // 打包時配置
├── screenshots // 專案截圖,和專案開發無關
├── src // 原始碼目錄
│ ├── components // 元件
│ ├── config // 專案開發配置
│ ├── images // 圖片檔案
│ ├── models // redux models
│ ├── pages // 頁面檔案目錄
│ │ └── home
│ │ ├── index.js // 頁面邏輯
│ │ ├── index.scss // 頁面樣式
│ │ ├── model.js // 頁面models
│ │ └── service.css // 頁面api
│ ├── styles // 樣式檔案
│ ├── utils // 常用工具類
│ ├── app.js // 入口檔案
│ └── index.html
├── package.json
└── template.js // pages模版快速生成指令碼,執行命令 npm run tep `檔名`
複製程式碼
#寫在最後 專案完整程式碼地址
git分支說明:
init:框架整體結構,不涉及任何業務邏輯
master:專案的穩定版本
feature:專案開發分支
後續我會加入一些業務程式碼和小程式、H5的線上二維碼,方面大家學習和交流