翻译 | 《JavaScript Everywhere》第22章 移动应用程序shell
写在最前面
大家好呀,我是毛小悠,是一位前端开发工程师。正在翻译一本英文技术书籍。
为了提高大家的阅读体验,对语句的结构和内容略有调整。如果发现本文中有存在瑕疵的地方,或者你有任何意见或者建议,可以在评论区留言,或者加我的微信:code_maomao,欢迎相互沟通交流学习。
(σ゚∀゚)σ..:*☆哎哟不错哦
第22章 移动应用程序shell
我妻子是一位摄影师,这意味着她的大部分生活都是基于在矩形框中构图。在摄影中,有很多变量-物体,光线,角度,但是图像的比例保持一致。在这种限制下,不可思议的事情发生了,塑造了我们看待和记住周围世界的方式。移动应用程序开发提供了类似的机会。在小巧的矩形屏幕的约束下,我们可以构建具有沉浸式用户体验的功能强大的应用程序。
在本章中,我们将开始为应用程序构建shell
。为此,我们首先将仔细研究React Native
组件的一些关键构建块。然后,我们将通过React Native
的内置样式支持以及我们选择的CSS-in-JS
库样式组件,研究如何将样式应用于我们的应用程序。在介绍了如何应用样式之后,我们将看看如何将路由集成到我们的应用程序中。最后,我们将探索如何使用图标轻松增强我们的应用程序界面。
React Native构建块
让我们先来看一下React Native
应用程序的基本构建块。你可能已经猜到React Native
应用程序包含用JSX
编写的React
组件。但是,如果没有HTML
页面的DOM
(文档对象模块),这些组件到底有什么用?我们可用于从src/Main.js
的“ Hello World
”组件开始。现在,我已经删除了样式:
import React from 'react';
import { Text, View } from 'react-native';
const Main = () => {
return (
Hello world!
);
};
export default Main;
在此标记中,有两个著名的JSX
标签 :
和 .
。如果你有网页开发经验,就知道标签与标签的用途大致相同。它是我们应用程序内容的容器。靠它们自己并不能做很多事,但是它们包含了我们应用程序的所有内容,可以相互嵌套,并可以应用样式。我们的每个组件都将包含在中。
在React Native
中,你可以在Web
任何地方使用标签。毫无疑问,该标签用于包含我们应用中的任何文本。
但是,与网页不同,该标签用于所有文本。我们还可以通过使用JSX
元素来添加图片到我们的应用中。
让我们更新我们的 src/Main.js
文件以包含图像。要做到这一点,我们从React Native导入了Image
组件并使用一个有src属性的标记(见图22-1
):
import React from 'react';
import { Text, View, Image } from 'react-native';
const Main = () => {
return (
Hello world!
);
};
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 (
Hello world!
);
};
图22-2
使用样式我们可以调整<Text
>元素的外观
你可能会认为,在元素级别应用样式会很快变得难以维护。我们可以使用React Native
的StyleSheet
库来帮助组织和重用我们的样式。
首先,我们需要将StyleSheet
添加到导入列表中(图22-3
):
import { Text, View, Image, StyleSheet } from 'react-native';
现在我们可以抽象出样式:
const Main = () => {
return (
Hello world!
This is my app
);
};
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/s...]
图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 (
Hello world!
This is my app.
);
};
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 (
Favorites
);
};
export default Favorites;
在src/screens/feed.js
中添加它:
import React from 'react';
import { Text, View } from 'react-native';
const Feed = () => {
return (
Feed
);
};
export default Feed;
最后,将其添加到src/screens/mynotes.js
中:
import React from 'react';
import { Text, View } from 'react-native';
const MyNotes = () => {
return (
My Notes
);
};
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 ;
};
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 (
This is a note!
);
};
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 (
Note Feed
);
};
这样,我们应该能够在屏幕之间进行导航。单击“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
中,包括设置属性,例如大小和颜色:
我们将图标添加到标签导航中。React Navigation
包含一个名为tabBarIcon
的属性,该属性允许我们设置图标。我们可以将此作为函数传递,使我们能够设置tintColor
,以便活动选项卡图标的颜色与非活动图标的颜色不同:
const TabNavigator = createBottomTabNavigator({
FeedScreen: {
screen: FeedStack,
navigationOptions: {
tabBarLabel: 'Feed',
tabBarIcon: ({ tintColor }) => (
)
}
},
MyNoteScreen: {
screen: MyStack,
navigationOptions: {
tabBarLabel: 'My Notes',
tabBarIcon: ({ tintColor }) => (
)
}
},
FavoriteScreen: {
screen: FavStack,
navigationOptions: {
tabBarLabel: 'Favorites',
tabBarIcon: ({ tintColor }) => (
)
}
}
});
图22-7
我们应用程序的导航现在包括图标
结论
在本章中,我们介绍了如何构建React Native
应用程序的基本组件。现在,你可以创建组件,向其中添加样式并在它们之间导航。希望通过此基本设置,你可以看到React Native
的惊人潜力。借助最少的新技术,你已经可以打造令人印象深刻且专业的移动应用程序的起点。在下一章中,我们将使用GraphQL
在应用程序中包含来自API
的数据。
如果有理解不到位的地方,欢迎大家纠错。如果觉得还可以,麻烦您点赞收藏或者分享一下,希望可以帮到更多人。