翻譯 | 《JavaScript Everywhere》第22章 移動應用程序shell前端
寫在最前面
你們好呀,我是毛小悠,是一位前端開發工程師。正在翻譯一本英文技術書籍。react
爲了提升你們的閱讀體驗,對語句的結構和內容略有調整。若是發現本文中有存在瑕疵的地方,或者你有任何意見或者建議,能夠在評論區留言,或者加個人微信:code_maomao,歡迎相互溝通交流學習。git
(σ゚∀゚)σ..:*☆哎喲不錯哦github
第22章 移動應用程序shell
我妻子是一位攝影師,這意味着她的大部分生活都是基於在矩形框中構圖。在攝影中,有不少變量-物體,光線,角度,可是圖像的比例保持一致。在這種限制下,難以想象的事情發生了,塑造了咱們看待和記住周圍世界的方式。移動應用程序開發提供了相似的機會。在小巧的矩形屏幕的約束下,咱們能夠構建具備沉浸式用戶體驗的功能強大的應用程序。算法
在本章中,咱們將開始爲應用程序構建shell
。爲此,咱們首先將仔細研究React Native
組件的一些關鍵構建塊。而後,咱們將經過React Native
的內置樣式支持以及咱們選擇的CSS-in-JS
庫樣式組件,研究如何將樣式應用於咱們的應用程序。在介紹瞭如何應用樣式以後,咱們將看看如何將路由集成到咱們的應用程序中。最後,咱們將探索如何使用圖標輕鬆加強咱們的應用程序界面。shell
React Native構建塊
讓咱們先來看一下React Native
應用程序的基本構建塊。你可能已經猜到React Native
應用程序包含用JSX
編寫的React
組件。可是,若是沒有HTML
頁面的DOM
(文檔對象模塊),這些組件到底有什麼用?咱們可用於從src/Main.js
的「 Hello World
」組件開始。如今,我已經刪除了樣式:npm
import React from 'react'; import { Text, View } from 'react-native'; const Main = () => { return ( <View> <Text>Hello world!</Text> </View> ); }; export default Main;
在此標記中,有兩個著名的JSX
標籤 :
和 .
。若是你有網頁開發經驗,就知道標籤與標籤的用途大體相同。它是咱們應用程序內容的容器。靠它們本身並不能作不少事,可是它們包含了咱們應用程序的全部內容,能夠相互嵌套,並能夠應用樣式。咱們的每一個組件都將包含在中。react-native
在React Native
中,你能夠在Web
任何地方使用標籤。毫無疑問,該標籤用於包含咱們應用中的任何文本。bash
可是,與網頁不一樣,該標籤用於全部文本。咱們還能夠經過使用JSX
元素來添加圖片到咱們的應用中。微信
讓咱們更新咱們的* src/Main.js
*文件以包含圖像。要作到這一點,咱們從React Native導入了Image
組件並使用一個有src屬性的標記(見圖22-1
):
import React from 'react'; import { Text, View, Image } from 'react-native'; const Main = () => { return ( <View style={{ flex: 1, justifyContent: 'center', alignItems: 'center' }}> <Text>Hello world!</Text> <Image source={require('../assets/images/hello-world.jpg')} /> </View> ); }; export default Main;
前面的代碼在視圖中渲染了一些文本和圖像。你可能會注意到,咱們的標記和JSX
標記是傳遞的屬性,這些屬性使咱們可以控制特定的行爲(在這種狀況下,是視圖的樣式和圖像的來源)。
將屬性傳遞給元素可使咱們擴展元素的各類附加功能。React Native
的API
文檔對每一個元素可用的屬性進行了分類。
圖22-1
。使用<Image
>標籤,咱們能夠將圖像添加到咱們的應用程序中(Windell Oskay
攝)
咱們的應用程序並無作不少事情,可是在下一節中,咱們將探討如何使用React Native
的內置樣式支持和樣式化組件來改善外觀。
樣式和樣式組件
做爲應用程序開發人員和設計師,咱們但願可以對應用程序進行樣式設置,能夠具備良好的外觀、感受和用戶體驗。有許多UI
組件庫,例如NativeBase
或React Native Elements
,一般提供了許多預約義且可自定義的組件。
這些都是值得一看的,但出於咱們的目的,讓咱們探索如何組合本身應用程序的樣式和佈局。
正如咱們已經看到的,React Native
提供了一個style
屬性,該屬性容許咱們將自定義樣式應用於應用程序中的任何JSX
元素。樣式名稱和值與CSS
的樣式名稱和值匹配,除了名稱使用camelCase
編寫外,例如lineHeight
和backgroundColor
。讓咱們更新/src/Main.js
文件,使其包含元素的某些樣式(參見圖22-2
):
const Main = () => { return ( <View style={{ flex: 1, justifyContent: 'center', alignItems: 'center' }}> <Text style={{ color: '#0077cc', fontSize: 48, fontWeight: 'bold' }}> Hello world! </Text> <Image source={require('../assets/images/hello-world.jpg')} /> </View> ); };
圖22-2
使用樣式咱們能夠調整<Text
>元素的外觀
你可能會認爲,在元素級別應用樣式會很快變得難以維護。咱們可使用React Native
的StyleSheet
庫來幫助組織和重用咱們的樣式。
首先,咱們須要將StyleSheet
添加到導入列表中(圖22-3
):
import { Text, View, Image, StyleSheet } from 'react-native';
如今咱們能夠抽象出樣式:
const Main = () => { return ( <View style={styles.container}> <Text style={styles.h1}>Hello world!</Text> <Text style={styles.paragraph}>This is my app</Text> <Image source={require('../assets/images/hello-world.jpg')} /> </View> ); }; const styles = StyleSheet.create({ container: { flex: 1, justifyContent: 'center' }, h1: { fontSize: 48, fontWeight: 'bold' }, paragraph: { marginTop: 24, marginBottom: 24, fontSize: 18 } });
彈性盒Flexbox
React Native
使用CSS flexbox
算法定義佈局樣式。咱們不會深刻介紹flexbox
,可是React Native
提供的文檔清楚地說明了flexbox
及其如何在屏幕上排列元素的案例。
[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-z9Ipy9fi-1606433567748)(http://vipkshttp0.wiz.cn/ks/share/resources/c46f74f8-50d4-4015-8658-189fa6382bb9/3605e53d-a36d-4996-be90-cd98a055256a/index_files/3d8da063-0966-4016-892e-47d00d20fd54.jpg)]
圖22-3
經過使用樣式表,咱們能夠縮放應用程序的樣式
樣式化的組件
儘管React Native
的內置樣式屬性和StyleSheets
能夠提供咱們開箱即用的全部功能,但它們遠不是咱們設計應用程序樣式的惟一選擇。
咱們還能夠利用流行的Web CSS-in-JS
解決方案,例如Styled Components
和Emotion
。我認爲這些提供了更簡潔的語法,與CSS
更加緊密地結合在一塊兒,並限制了Web
和移動應用程序代碼庫之間所需的轉換的代碼量。使用這些啓用了Web CSS-in-JS
庫也爲跨平臺共享樣式或組件創造了機會。爲了實現咱們的目的,讓咱們看一下如何使上一個示例適應使用Styled Components
庫。首先,在src/Main.js
中,咱們將導入庫的本機版本:
import styled from 'styled-components/native'
從這裏咱們能夠將樣式遷移到樣式化組件語法。若是已經按照了第13
章的說明進行操做,則此語法應該很是熟悉。咱們的src/Main.js
文件的最終代碼變爲:
import React from 'react'; import { Text, View, Image } from 'react-native'; import styled from 'styled-components/native'; const StyledView = styled.View` flex: 1; justify-content: center; `; const H1 = styled.Text` font-size: 48px; font-weight: bold; `; const P = styled.Text` margin: 24px 0; font-size: 18px; `; const Main = () => { return ( <StyledView> <H1>Hello world!</H1> <P>This is my app.</P> <Image source={require('../assets/images/hello-world.jpg')} /> </StyledView> ); }; export default Main;
樣式化的組件大寫
在樣式化組件庫中,元素名稱必須始終大寫。這樣,咱們如今能夠將自定義樣式應用於咱們的應用程序,並能夠選擇使用React Native
的內置樣式系統或樣式化組件庫。
路由
在網頁上,咱們可使用HTML
錨連接將一個HTML
文檔連接到任何其餘文檔,包括咱們本身網站上的文檔。對於JavaScript
驅動的應用程序,咱們使用路由將JavaScript
渲染的模板連接在一塊兒。那麼移動應用程序呢?對於這些,咱們將在屏幕之間路由用戶。在本節中,咱們將探討兩種常見的路由類型:基於選項卡的導航和堆棧導航。
使用React
導航的選項卡式路由
爲了執行路由,咱們將利用React Navigation
庫,這是React Native
和Expo
團隊推薦的路由解決方案。最重要的是,它使實現帶有平臺特定的外觀通用路由模式變得很是簡單。
首先,讓咱們首先在src
目錄中建立一個名爲screens
的新目錄。在screens
目錄中,讓咱們建立三個新文件,每一個文件包含一個很是基本的React
組件。
在src/screens/favorites.js
中添加如下內容:
import React from 'react'; import { Text, View } from 'react-native'; const Favorites = () => { return ( <View style={{ flex: 1, justifyContent: 'center', alignItems: 'center' }}> <Text>Favorites</Text> </View> ); }; export default Favorites;
在src/screens/feed.js
中添加它:
import React from 'react'; import { Text, View } from 'react-native'; const Feed = () => { return ( <View style={{ flex: 1, justifyContent: 'center', alignItems: 'center' }}> <Text>Feed</Text> </View> ); }; export default Feed;
最後,將其添加到src/screens/mynotes.js
中:
import React from 'react'; import { Text, View } from 'react-native'; const MyNotes = () => { return ( <View style={{ flex: 1, justifyContent: 'center', alignItems: 'center' }}> <Text>My Notes</Text> </View> ); }; export default MyNotes;
而後,咱們能夠在src/screens/index.js
中建立一個新文件,用做咱們應用程序路由的根目錄。咱們將從導入初始的react
和react-navigation
依賴關係開始:
import React from 'react'; import { createAppContainer } from 'react-navigation'; import { createBottomTabNavigator } from 'react-navigation-tabs'; // import screen components import Feed from './feed'; import Favorites from './favorites'; import MyNotes from './mynotes';
導入這些依賴項後,咱們可使用React Navigation
的createBottomTabNavigator
,在這三個屏幕之間建立一個標籤導航器,定義應在咱們的導航中顯示哪些React
組件屏幕:
const TabNavigator = createBottomTabNavigator({ FeedScreen: { screen: Feed, navigationOptions: { tabBarLabel: 'Feed', } }, MyNoteScreen: { screen: MyNotes, navigationOptions: { tabBarLabel: 'My Notes', } }, FavoriteScreen: { screen: Favorites, navigationOptions: { tabBarLabel: 'Favorites', } } }); // create the app container export default createAppContainer(TabNavigator);
最後,讓咱們更新src/Main.js
文件,除了導入路由器以外什麼也不作。如今應簡化爲如下內容:
import React from 'react'; import Screens from './screens'; const Main = () => { return <Screens />; }; export default Main;
經過在終端中輸入npm start
命令,確保你的應用程序正在運行。如今,你應該在屏幕底部看到選項卡導航,在其中點擊選項卡會將你轉到適當的屏幕(圖22-4
)。
圖22-4
如今咱們可使用選項卡式導航在屏幕之間導航
堆棧導航
第二種路由選擇類型是堆棧導航,其中概念上將屏幕「堆疊」在一塊兒,從而使用戶能夠更深刻地瀏覽堆棧。考慮一個新聞應用程序,用戶在其中查看文章的摘要。用戶能夠點擊新聞文章標題,並在堆棧中更深刻地瀏覽到文章內容。 而後,他們能夠單擊「後退」按鈕,導航迴文章提要,或者導航到另外一個文章標題,從而更深刻地瀏覽堆棧。
在咱們的應用程序中,咱們但願用戶可以從筆記的摘要切換到筆記自己並返回。 讓咱們看看如何爲每一個屏幕實現堆棧導航。首先,讓咱們建立一個新的NoteScreen
組件,它將包含堆棧中的第二個屏幕。使用最少的React Native
組件在src/screens/note.js
上建立一個新文件:
import React from 'react'; import { Text, View } from 'react-native'; const NoteScreen = () => { return ( <View style={{ padding: 10 }}> <Text>This is a note!</Text> </View> ); }; export default NoteScreen;
接下來,咱們將對路由器進行更改,啓用NoteScreen
組件的堆疊導航。爲此,咱們將從react-navigation-stack
以及新的note.js
組件導入createStackNavigator
。在src/screens/index.js
中,將導入內容更新以下:
import React from 'react'; import { Text, View, ScrollView, Button } from 'react-native'; import { createAppContainer } from 'react-navigation'; import { createBottomTabNavigator } from 'react-navigation-tabs'; // add import for createStackNavigator import { createStackNavigator } from 'react-navigation-stack'; // import screen components, including note.js import Feed from './feed'; import Favorites from './favorites'; import MyNotes from './mynotes'; import NoteScreen from './note';
經過導入咱們的庫和文件,咱們能夠實現堆棧導航功能。在咱們的路由器文件中,咱們必須告訴React Navigation
哪些屏幕是「可重疊的」。對於咱們每一個選項卡式路由,咱們但願用戶可以導航到「筆記」屏幕。繼續並按以下所示定義這些堆棧:
const FeedStack = createStackNavigator({ Feed: Feed, Note: NoteScreen }); const MyStack = createStackNavigator({ MyNotes: MyNotes, Note: NoteScreen }); const FavStack = createStackNavigator({ Favorites: Favorites, Note: NoteScreen });
如今,咱們能夠更新TabNavigator
來引用堆棧,而不是單個屏幕。爲此,請更新每一個TabNavigator
對象中的screen
屬性:
const TabNavigator = createBottomTabNavigator({ FeedScreen: { screen: FeedStack, navigationOptions: { tabBarLabel: 'Feed' } }, MyNoteScreen: { screen: MyStack, navigationOptions: { tabBarLabel: 'My Notes' } }, FavoriteScreen: { screen: FavStack, navigationOptions: { tabBarLabel: 'Favorites' } } });
總之,咱們的src/screens/index.js
文件應以下所示:
import React from 'react'; import { Text, View, ScrollView, Button } from 'react-native'; import { createAppContainer } from 'react-navigation'; import { createBottomTabNavigator } from 'react-navigation-tabs'; import { createStackNavigator } from 'react-navigation-stack'; // import screen components import Feed from './feed'; import Favorites from './favorites'; import MyNotes from './mynotes'; import NoteScreen from './note'; // navigation stack const FeedStack = createStackNavigator({ Feed: Feed, Note: NoteScreen }); const MyStack = createStackNavigator({ MyNotes: MyNotes, Note: NoteScreen }); const FavStack = createStackNavigator({ Favorites: Favorites, Note: NoteScreen }); // navigation tabs const TabNavigator = createBottomTabNavigator({ FeedScreen: { screen: FeedStack, navigationOptions: { tabBarLabel: 'Feed' } }, MyNoteScreen: { screen: MyStack, navigationOptions: { tabBarLabel: 'My Notes' } }, FavoriteScreen: { screen: FavStack, navigationOptions: { tabBarLabel: 'Favorites' } } }); // create the app container export default createAppContainer(TabNavigator);
若是咱們在模擬器或設備上的Expo
應用程序中打開應用程序,則不會發現明顯區別。這是由於咱們還沒有向堆疊導航添加連接。讓咱們更新src/screens/feed.js
組件以包括一個堆疊的導航連接。
爲此,首先包括React Native
的Button
依賴項:
import { Text, View, Button } from 'react-native';
如今,咱們能夠包括一個按鈕,在按下該按鈕時,將導航到note.js
組件的內容。咱們將傳遞組件props
,其中將包含導航信息,並添加一個包含標題和onPress
道具的:
const Feed = props => { return ( <View style={{ flex: 1, justifyContent: 'center', alignItems: 'center' }}> <Text>Note Feed</Text> <Button title="Keep reading" onPress={() => props.navigation.navigate('Note')} /> </View> ); };
這樣,咱們應該可以在屏幕之間進行導航。單擊「Feed」屏幕中的按鈕以導航至「Node」屏幕,而後單擊箭頭以返回(圖22-5
)。
圖22-5
單擊按鈕連接將導航到新屏幕,而單擊箭頭將使用戶返回上一屏幕
添加屏幕標題
添加堆棧導航器會自動在咱們的應用程序頂部添加標題欄。咱們能夠設置樣式,甚至刪除該頂部欄。如今,讓咱們在堆棧頂部的每一個屏幕上添加一個標題。爲此,咱們將在組件自己以外設置組件NavigationOptions
。在src/screens/feed.js
中:
import React from 'react'; import { Text, View, Button } from 'react-native'; const Feed = props => { // component code }; Feed.navigationOptions = { title: 'Feed' }; export default Feed;
咱們能夠對其餘屏幕組件重複此過程。
在src/screens/favorites.js
中:
Favorites.navigationOptions = { title: 'Favorites' };
在src/screens/mynotes.js
中:
MyNotes.navigationOptions = { title: 'My Notes' };
如今,咱們每一個屏幕的頂部導航欄都將包含一個標題(圖22-6
)。
圖22-6
在navigationOptions
中設置標題會將其添加到頂部導航欄
Icons
目前,咱們的導航功能已完成,但缺乏可視化組件以使用戶使用更友好。值得慶幸的是,Expo
使在咱們的應用程序中包含圖標變得異常容易。咱們能夠搜索Expo
提供的全部圖標expo.github.io/vector-icons
。包括許多圖標集,例如Ant Design
,Ionicons
,Font Awesome
,Entypo
,Foundation
,Material
圖標和Material Community
圖標。這爲咱們提供了開箱即用的多種選擇。
讓咱們在選項卡式導航中添加一些圖標。首先,咱們必須導入咱們要使用的圖標集。在咱們的案例中,咱們將經過在src/screens/index.js
中添加如下內容來使用Material Community
圖標:
import { MaterialCommunityIcons } from '@expo/vector-icons';
如今,咱們想在組件中使用圖標的任何地方,均可以將其包含在JSX
中,包括設置屬性,例如大小和顏色:
<MaterialCommunityIcons name="star" size={24} color={'blue'} />
咱們將圖標添加到標籤導航中。React Navigation
包含一個名爲tabBarIcon
的屬性,該屬性容許咱們設置圖標。咱們能夠將此做爲函數傳遞,使咱們可以設置tintColor
,以便活動選項卡圖標的顏色與非活動圖標的顏色不一樣:
const TabNavigator = createBottomTabNavigator({ FeedScreen: { screen: FeedStack, navigationOptions: { tabBarLabel: 'Feed', tabBarIcon: ({ tintColor }) => ( <MaterialCommunityIcons name="home" size={24} color={tintColor} /> ) } }, MyNoteScreen: { screen: MyStack, navigationOptions: { tabBarLabel: 'My Notes', tabBarIcon: ({ tintColor }) => ( <MaterialCommunityIcons name="notebook" size={24} color={tintColor} /> ) } }, FavoriteScreen: { screen: FavStack, navigationOptions: { tabBarLabel: 'Favorites', tabBarIcon: ({ tintColor }) => ( <MaterialCommunityIcons name="star" size={24} color={tintColor} /> ) } } });
這樣,咱們的選項卡式導航將顯示圖標(圖22-7
)。
圖22-7
咱們應用程序的導航如今包括圖標
結論
在本章中,咱們介紹瞭如何構建React Native
應用程序的基本組件。如今,你能夠建立組件,向其中添加樣式並在它們之間導航。但願經過此基本設置,你能夠看到React Native
的驚人潛力。藉助最少的新技術,你已經能夠打造使人印象深入且專業的移動應用程序的起點。在下一章中,咱們將使用GraphQL
在應用程序中包含來自API
的數據。
若是有理解不到位的地方,歡迎你們糾錯。若是以爲還能夠,麻煩您點贊收藏或者分享一下,但願能夠幫到更多人。