Taro框架的簡介和開篇介紹
Taro是由京東凹凸實驗室推出的框架,目的就是解決多端混亂的局面,也是當下比較新興的一個框架。
當我們按照一種模式一種代碼進行開發,開發完成后,項目就有了在任何終端顯示的能力,這是一種想想都很爽的。那具體Taro有那些優點,請看下面的圖片。
目前Taro支持的終端
- 微信小程序
- H5 移動端Web頁面
- 百度小程序
- 支付寶小程序
- 快應用
- ReactNative
- 字節跳動小程序
- QQ輕應用
是目前支持小程序最多的前端框架,並且支持ReactNatvie,說明我們可以輕易的生成媲美原生的APP應用。所以公司的應用如果想全網推廣,占用最多的流量入口的話,使用Taro就完全沒有問題。
有熟悉uni的同學會講uni也有這樣類似的功能,生成多端應用的功能,而且還有專屬的編輯器,調試很方便,下邊就放一個taro與uni-app以及其他例如mpvue等的對比圖
由此可見,Taro 的強大之處,以及Taro框架在前端的技術的占比會越來越高。而且用統一的框架、統一的API、統一的代碼規范以及統一的代碼結構,是多么棒的開發體驗。
一次開發就可以完成所有主流平台的布局,人力和時間成本壓縮到最低,感覺節省了一個億哦。
下邊我們就一起來揭秘Taro這神奇的面紗把
Taro的環境搭建和Hello World
前置知識
學習這個前端框架,你需要一些前置知識:
- HTML、CSS,JavaScript這三個是基礎知識,最起碼要了解能作出簡單的靜態頁面
- 理解MVVM框架,如果會React框架是最好的
- 了解ES6相關語法,作為一個當下流行的框架以及2020年的前端開發用ES6讓代碼規范起來,對項目開發和管理更加的方便
Taro編譯工具的介紹
Taro是一套遵循React語法規范的多端開發解決方案,使用Taro,只書寫一套代碼,再通過Taro的編譯工具,講源代碼分別編譯出可以再不同端(微信小程序,H5,RN等)運行代碼。
所以說這里的Taro編譯工具是非常重要的,這里附帶一張圖。
Taro開發環境的安裝
1.第一步是安裝@tarojs/cli(腳手架工具),也有教開發工具的。
這個你可以使用npm或者yarn進行全局安裝,命令如下:
npm的安裝方式
npm install -g @tarojs/cli
yarn的安裝方式
yarn global add @tarojs/cli
打開命令行后,輸入上邊的命令。
2.安裝完成后,就可以用腳手架創建項目,命令如下:
taro init taro-dome
這里有個小坑就是如果你使用npm來安裝腳手架的時候,有很大機率會失敗,這些失敗多是因為國內網絡環境限制的。有兩種解決方案,第一是"fangqiang"來進行安裝,第二種是使用yarn來進行暗轉,我這里就使用了yarn。
Hello World程序
通過上邊的創建項目,我們的項目已經建立好了,然后就是運行項目,命令如下:
cd taro-dome
npm run dev:h5
在這里運行的是h5模式的,如果要運行小程序的根據package.json中的script設置可知相應的運行方式。
運行后頁面會在瀏覽器顯示Hello World,默認的端口為10086,如圖:
Taro生成小程序代碼並預覽
Taro可以生成多端代碼,在上一節只生成了h5的顯示,這次我們就先來進行生成小程序代碼,並進行預覽。
生成微信小程序的代碼
npm run dev:weapp
輸入完命令后,taro編譯器自動為我們生成小程序代碼到dist目錄中。
這里邊的app.js、app.json以及app.wxss 這都是微信小程序所對應的文件,有過微信小程序開發的肯定覺得很熟悉,這就是Taro的強大之處,也是Taro框架的開發者肯定是個webpack開發的大牛,編譯生成對應的終端的代碼,而不是一個殼子嵌套。
在微信開發者工具中預覽項目
開發小程序的肯定知道微信開發者工具,如果你是初學的這里給你一個下載的鏈接,方便下載學習:
https://developers.weixin.qq.com/miniprogram/dev/devtools/download.html
下載后安裝步驟很簡單,跟安裝QQ幾乎一樣。
安裝完成后,你需要注冊一個賬號,這個自己按照提示注冊就可以了。
注冊后導入一個小程序項目
需要注意的是這不是新建,而是導入一個項目。目錄選擇的是你的taro項目剛才編譯后生成的dist目錄
AppId如果有在公眾平台注冊可以填,沒有默認是一個測試號直接導入即可。
導入后你就可以看到在微信開發者工具中顯示Hello World!了。
注意坑點
千萬不要在微信開發者工具中修改dist目錄,因為這個文件是由taro編譯而來的;
如果要修改在taro的原項目修改,然后通過編譯將修改的內容編譯到dist文件中
Taro的目錄介紹
在目錄介紹前肯定會有疑惑,Taro是多端統一框架,前邊我們利用編譯工具生成了h5和微信小程序的代碼,那么其他的支付寶小程序、百度小程序等又是如何生成?
這些的答案都在項目的package.json文件中的scripts部分當中:
"scripts": { "build:weapp": "taro build --type weapp", "build:swan": "taro build --type swan", "build:alipay": "taro build --type alipay", "build:tt": "taro build --type tt", "build:h5": "taro build --type h5", "build:rn": "taro build --type rn", "build:qq": "taro build --type qq", "build:quickapp": "taro build --type quickapp", "dev:weapp": "npm run build:weapp -- --watch", "dev:swan": "npm run build:swan -- --watch", "dev:alipay": "npm run build:alipay -- --watch", "dev:tt": "npm run build:tt -- --watch", "dev:h5": "npm run build:h5 -- --watch", "dev:rn": "npm run build:rn -- --watch", "dev:qq": "npm run build:qq -- --watch", "dev:quickapp": "npm run build:quickapp -- --watch" },
我們就以dev為例解釋下dev: 后邊的都是哪一個平台的
- weapp 微信小程序
- h5 手機web用於公眾號和瀏覽器等
- swan 百度小程序
- alipay 支付寶小程序
- tt 字節跳動小程序
- qq QQ小程序
- jd 京東小程序
- quickapp 快應用
- rn React Native
這些類型執行都和微信小程序的一樣,都是將: 后的改成相對應的模式即可
npm run dev:weapp 或 yarn dev:weapp
下邊就介紹下Taro的項目目錄結構
dist目錄
這個目錄在上邊生成微信小程序代碼時已經見到了,是我們在預覽時自動生成的,每次進行預覽都會根據我們預覽的終端不同,編譯成不同代碼。
每次編譯時都會刪除以前的代碼,這個小伙伴么要注意一下。
config目錄
這個就是項目的一些配置,這些配置以后會不斷深入學習,但是現在還不了解,可以先不進行配置。否則會影響項目的運行。
node_modules
項目所需的依賴包,就是使用npm install進行安裝的包,一般不需要修改。
src目錄
這個是最重要的,這個是我們的源碼目錄,開發的所有代碼都在這個里邊。
下邊給一個官方的目錄結構說明
├── dist 編譯結果目錄
├── config 配置目錄
| ├── dev.js 開發時配置 | ├── index.js 默認配置 | └── prod.js 打包時配置 ├── src 源碼目錄 | ├── pages 頁面文件目錄 | | ├── index index 頁面目錄 | | | ├── index.js index 頁面邏輯 | | | └── index.css index 頁面樣式 | ├── app.css 項目總通用樣式 | └── app.js 項目入口文件 └── package.json
Taro使用Hooks的新特性
React Hooks的優缺點
既然我們要用Hooks來寫,我們就要了解React Hooks的優缺點,為什么要用Hooks,那么我們就來看下Hooks的優缺點吧!
這個優缺點是通過和傳統的React.Component進行對比得出的。
React Hooks的優點
- 更容易復用代碼
- 清爽的代碼風格
- 代碼量更少
- 更容易發現無用的狀態和函數
- 更容易拆分組件
React Hooks的缺點
- 狀態不同步
- 副作用代碼從主動式變成響應式
如何避免React Hooks的常見問題
- 不要在useEffect里面寫太多的依賴項,划分這些依賴項成多個useEffect,這樣更好維護
- 如果你碰到狀態不同步的問題,可以考慮下手動傳遞參數到函數。如:
// showCount的count來自父級作用域 const [count,setCount] = useState(xxx); function showCount(){ console.log(count) } // showCount的count來自參數 const [count,setCount] = useState(xxx); function showCount(c){ console.log(c) }
- 一定要加入eslint-plugin-react-hooks這個插件,並且重視它的警告
- 使用useRef來保存你的引用並在re-render的時候主動更新ref的對應屬性,這樣可以避免“引用是舊”的這個煩人的問題,但這種方式hack味道濃郁。
使用Hooks來改寫Index組件
在src/pages/index/index.jsx文件:
原文件:
import Taro, { Component } from '@tarojs/taro' import { View, Text } from '@tarojs/components' import './index.less' export default class Index extends Component { componentWillMount () { } componentDidMount () { } componentWillUnmount () { } componentDidShow () { } componentDidHide () { } config = { navigationBarTitleText: '首頁' } render () { return ( <View className='index'> <Text>Hello world!</Text> </View> ) } }
修改成hooks方式:
import Taro, { useState } from '@tarojs/taro' import { View, Text } from '@tarojs/components' import './index.less' function Index(){ const [userName] = useState('Hello Taro!') return ( <View> <Text>{userName}</Text> </View> ) } export default Index
如果你對React Hooks不熟悉的話,這里有一套免費的Hooks學習視頻教程:https://www.jspang.com/detailed?id=59
如果您對React也不太熟悉的話,沒關系這邊有一整套的React學習視頻,學習完后上手項目沒有問題的:https://jspang.com/detailed?id=56
Taro中組件傳值
使用Taro 的一個好處就是要可以用組件化的方式進行編程,所以編寫組件在Taro中是每天都需要作的工作。
下邊我們先來創建一個自組件,然后進行組件的傳值,Taro的組件傳值跟React的一樣利用props,因此如果你對React的組件傳值比較熟悉的化,這里很容易理解。
在Taro項目中的src/pages/index文件夾下面建立一個Child組件
child.jsx組件
import { View, Text } from '@tarojs/components' function Child(){ return ( <View><Text>我是子組件</Text></View> ) }
然后在Index組件中引入,這里給出全部代碼方便學習
import Taro, { useState } from '@tarojs/taro' import { View, Text } from '@tarojs/components' import './index.less' import Child from "./child" function Index(){ const [userName] = useState('Hello Taro!') return ( <View> <Text>{userName}</Text> <Child></Child> </View> ) } export default Index
父組件向子組件傳值
在上邊說過,Taro的傳值跟React的一樣,父組件向子組件傳值是通過props進行;
在Taro中也是可以這樣傳值的,現在修改index.jsx代碼,把userName傳遞給子組件。
import Taro, { useState } from '@tarojs/taro' import { View, Text } from '@tarojs/components' import './index.less' import Child from "./child" function Index(){ const [userName] = useState('Hello Taro!') return ( <View> <Text>{userName}</Text> <Child userInfo={userName} ></Child> </View> ) } export default Index
傳遞后,子組件要增加props參數,然后才能用props進行接收。
import { View, Text } from '@tarojs/components' function Child(props){ return ( <View> <Text>我是子組件</Text> <View><Text>接收來自父組件的值:{props.userInfo}</Text></View> </View> ) } export default Child
這個組件間的傳值非常的簡單,當我們會用組件的形式編寫頁面和組件時,你就可以作一些小東西了。
但現在你可以看到,我們把頁面和組件放到了一個文件夾下,並且都使用了jsx擴展名。
那Taro時如何區分那些是組件,那些是頁面的?
其實它是通過自身的路由來區分的,只要配置路由的,就是頁面,沒配置的就默認是組件。
下邊我們來看下Taro中的路由吧!
Taro 路由配置和介紹
Taro中的路由和React 的路由不同,它是通過app.jsx中的pages來配置的,並且誰配置在第一個數組位置,誰就是默認打開的首頁。
首先配置路由
新建一個頁面
在/src/pages/文件夾下,建立一個/blog文件夾,在文件夾下面建立一個blog.jsx文件,寫入下面的代碼:
import {View , Text} from '@tarojs/components' function Blog(){ return ( <View> <Text>Blog Page</Text> </View> ) } export default Blog
路由配置
有了頁面之后就可以到/src/app.jsx下,然后在pages的數組里面加入代碼。
pages: [ 'pages/blog/blog', 'pages/index/index' ],
這里需要注意一點,就是你不需要用import引入Blog頁面,這個Taro為我們自動做好了。修改完成后,可以到瀏覽器中看一下,可以看到默認頁面已經變成了Blog頁面了。
頁面間的跳轉
頁面跳轉的方法
Taro提供了6個相關的導航API,我們可以使用這些API進行跳轉,需要注意的是這些有些是小程序專用的。
- navigateTo: 最基本的跳轉方式,可以返回上級頁面。三端都支持的,小程序、H5、React Native。
- redirectTo:不記錄上集頁面,直接跳轉。三端都支持的,小程序、H5、* React Native。
- switchTab: Tab之間進行切換,這個要配合Taro的導航欄一起使用,三端都支持的,小程序、H5、React Native。
- navigateBack: 返回上一級頁面,這個在小程序中常使用,三端都支持的,小程序、H5、React Native。
- relaunch:關閉所有額面,打開到應用內某個頁面。三端都支持的,小程序、H5、React Native。
- getCurrentPages: 獲取當前頁面信息所用,這個H5是不支持的。(注意)
頁面跳轉Demo
做個Demo,我們從Blog頁面,跳轉到Index頁面,我們的程序如何來編寫。
為了方便學習這里給出blog.jsx的全部代碼:
import Taro from '@tarojs/taro' import {View , Text ,Button} from '@tarojs/components' function Blog(){ const gotoIndex=()=>{ Taro.navigateTo({url:'/pages/index/index'}) } return ( <View> <Text>Blog Page</Text> <Button onClick={gotoIndex}>我要去Index頁面</Button> </View> ) } export default Blog
這樣我們就實現了Taro中路由的跳轉。
Taro路由傳參
Taro的路由傳參利用查詢字符串的形式
Taro中進行傳參,一般會使用查詢字符串的形式,也就是在跳轉的url上,加一個?問號的形式,然后后邊跟上參數。
現在我們就在Blog.jsx頁面用,useState的形式聲明一個變量,再通過跳轉把值帶到Index.jsx頁面。
import Taro ,{useState}from '@tarojs/taro' import {View , Text ,Button} from '@tarojs/components' function Blog(){ const [blogTitle,setBlogTitle]=useState('JSPang Blog') const gotoIndex=()=>{ Taro.navigateTo({url:'/pages/index/index?blogTitle='+blogTitle}) } return ( <View> <Text>Blog Page</Text> <Button onClick={gotoIndex}>我要去Index頁面</Button> </View> ) } export default Blog
接收傳遞參數並顯示在頁面上
在參數已經可以傳遞了,那如何在Index.jsx進行接收那,其實也非常簡單。只要使用this.$router.params就可以進行接收。
當然我們要接收參數,可以在useEffect()中進行(useEffect是React Hooks的方法,不了解的同學請去了解下),
useEffect(()=>{ setBlogTitle(this.$router.params.blogTitle) },[])
為了更好的學習,這給出接收的全部代碼,
index.jsx的代碼:
import Taro, { useState ,useEffect} from '@tarojs/taro' import { View, Text } from '@tarojs/components' import Child from './child.jsx' import './index.less' function Index(props){ const [userName ,setUserName] = useState('Hello World!!!!') const [blogTitle,setBlogTitle] = useState('') useEffect(()=>{ setBlogTitle(this.$router.params.blogTitle) },[]) return ( <View> <Text>{userName}</Text> <Child userName={userName}></Child> <View>{blogTitle}</View> </View> ) } export default Index
多參數的傳遞和接收
多個參數和多個參數的接收,傳遞的時候只要用&進行鏈接就可以了,比如下面這樣。(有前端開發經驗的同學,對這個肯定不會陌生)
Taro.navigateTo({url:'/pages/index/index?blogTitle='+blogTitle+'&introduce='+introduce})
為了學習方便,這里給出blog,jsx的全部代碼:
import Taro ,{useState}from '@tarojs/taro' import {View , Text ,Button} from '@tarojs/components' function Blog(){ introduce const [blogTitle,setBlogTitle]=useState('JSPangBlog') const [introduce,setIntroduce]=useState('111111') const gotoIndex=()=>{ Taro.navigateTo({url:'/pages/index/index?blogTitle='+blogTitle+'&introduce='+introduce}) } return ( <View> <Text>Blog Page</Text> <Button onClick={gotoIndex}>我要去Index頁面</Button> </View> ) } export default Blog
接收參數跟單參數接收方法一樣,不作過多介紹,直接給出代碼,
index.jsx代碼:
import Taro, { useState ,useEffect} from '@tarojs/taro' import { View, Text } from '@tarojs/components' import Child from './child.jsx' import './index.less' function Index(props){ const [userName ,setUserName] = useState('Hello World!!!!') const [blogTitle,setBlogTitle] = useState('') const [introduce,setIntroduce]=useState('') useEffect(()=>{ setBlogTitle(this.$router.params.blogTitle) setIntroduce(this.$router.params.introduce) },[]) return ( <View> <Text>{userName}</Text> <Child userName={userName}></Child> <View>{blogTitle}</View> <View>{introduce}</View> </View> ) } export default Index
JavaScript資源引入的方法
JavaScript的引入和React的引入方式差不多,比如現在我們定義了一個方法叫做XieDaJiao(謝大腳),然后再定義一個方法叫liuying(劉英)。
在/src目錄下,新建一個/tools文件夾,然后在文件夾下邊建立一個index.js文件,輸入下面的代碼。
export function xiedajiao(){ console.log('我是謝大腳') } export function liuying(){ console.log('我是劉英') }
建立完成后,我們在blog.jsx文件中引入這個,需要用ES的解構的方式引入:
import {xiedajiao,liuying} from '../../tools'
然后使用的方法,也是利用在useEffect中運行,如下:
useEffect(()=>{ xiedajiao() liuying() },[])
引入圖片的方式
Taro引入圖片的方式有兩種: import xxx from ‘…’ 然后用將xxx放到相應的src的方式和直接在src中用require方式
下方是blog.jsx的代碼,是用import的方式:
import Taro ,{useState ,useEffect}from '@tarojs/taro' import {View , Text ,Button,Image} from '@tarojs/components' import {xiedajiao,liuying} from '../../tools' import newbbd from '../../static/newbbd0001.jpg' function Blog(){ useEffect(()=>{ xiedajiao() liuying() },[]) const [blogTitle,setBlogTitle]=useState('JSPangBlog') const [introduce,setIntroduce]=useState('111111') const gotoIndex=()=>{ Taro.navigateTo({url:'/pages/index/index?blogTitle='+blogTitle+'&introduce='+introduce}) } return ( <View> <Text>Blog Page111</Text> <Button onClick={gotoIndex}>我要去Index頁面</Button> <View> <Image src={newbbd} width="100px" height="100px" /> </View> </View> ) }
如果想用require的方式,將Image組件的src屬性改為:
<Image src={require('../../static/newbbd0001.jpg')} width="100px" height="100px" />
更多資源的引入方式,可以來看下Taro資源引入的文檔:http://taro-docs.jd.com/taro/docs/static-reference.html
JSX的列表渲染
在開始介紹遠程數據請求前,先對JSX的列表渲染做下介紹,給JSX不熟悉的朋友提供便利。
構建數組對象
先使用JS的基本語法,打開blog.jsx文件然后再blog方法里編寫代碼:
const girls = [ {id:1,name:'胡一菲'}, {id:2,name:'陳美嘉'}, {id:3,name:'諸葛大力'}, {id:4,name:'咖喱醬'} ]
在JSX代碼中渲染列表
blog.jsx的全部代碼
import Taro ,{useState ,useEffect}from '@tarojs/taro' import {View , Text ,Button,Image} from '@tarojs/components' import {xiedajiao,liuying} from '../../tools' function Blog(){ useEffect(()=>{ xiedajiao() liuying() },[]) · const girls = [ {id:1,name:'胡一菲'}, {id:2,name:'陳美嘉'}, {id:3,name:'諸葛大力'}, {id:4,name:'咖喱醬'} ] const [blogTitle,setBlogTitle]=useState('JSPangBlog') const [introduce,setIntroduce]=useState('111111') const gotoIndex=()=>{ Taro.navigateTo({url:'/pages/index/index?blogTitle='+blogTitle+'&introduce='+introduce}) } return ( <View> <Text>Blog Page111</Text> <Button onClick={gotoIndex}>我要去Index頁面</Button> <View> { girls.map((item,index)=>{ return ( <View>{item.name}</View> ) }) } </View> </View> ) }
在JSX中使用邏輯判斷
在JSX中使用邏輯判斷,不能像下邊這樣用判斷:
<view> { if(zhujueNum===1){ return ('張偉') }else{ return('呂子喬') } } </view>
需要使用判斷要用三目運算符:
<view> 男主角是:{zhujueNum==1?'張偉':'呂子喬'} </view>
或者也可以使用,短路運算符:
<view> 男主角是:{zhujueNum==1 && '張偉' || '呂子喬'} </view>
請求遠程數據
Taro的遠程數據請求,利用Taro的request的方式,這里給出request的參數文檔:
```javascript
https://developers.weixin.qq.com/miniprogram/dev/api/network/request/wx.request.html
```
下邊我們在blog.jsx文件中,編寫一個testHandler方法,方法中使用Taro.request后去遠端數據,這里數據請求的路徑url,你可以去mockJs網站,也可以自己用node等方式創建一個數據請求路徑,或者你項目開發時候的路徑
const getData= ()=>{ Taro.request({ url:'...' }).then(res=>{ console.log(res.data) }) }
然后在JSX中編寫一個按鈕,加上onClick事件,代碼如下:
<Button onClick={getData}>獲取數據</Button>
遍歷渲染獲取到的數據
先用useState聲明一個articleList,代碼如下:
const [articleList,setArticleList] = useState([])
然后在return中使用map進行遍歷,如下:
{ articleList.map((item,index)=>{ return (<View key={index}>- {item.title} </View>) }) }
blog.jsx完整的代碼:
import Taro, { useState } from '@tarojs/taro' import { View, Text, Button } from '@tarojs/components' function Blog2(){ const [dataList, setDataList] = useState([]) const getData = () => { Taro.request({ url: 'https://apiblog.jspang.com/default/getArticleList' }) .then((res)=>{ console.log(res.data) setDataList(res.data.list) }) } return ( <View> <View><Text>數據請求</Text></View> <Button onClick={getData} >獲取數據</Button> <View> { dataList.map((item, index)=>{ return ( <View key={index} >{item.title}</View> ) }) } </View> </View> ) } export default Blog2