翻译 | 《JavaScript Everywhere》第22章 移动应用程序shell

翻译 | 《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 (
   <View>
    <Text>Hello world!</Text>
   </View>
  );
};

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 (
   <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 NativeAPI文档对每个元素可用的属性进行了分类。

在这里插入图片描述

22-1。使用<Image>标签,我们可以将图像添加到我们的应用程序中(Windell Oskay摄)

我们的应用程序并没有做很多事情,但是在下一节中,我们将探讨如何使用React Native的内置样式支持和样式化组件来改善外观。

样式和样式组件

作为应用程序开发人员和设计师,我们希望能够对应用程序进行样式设置,可以具有良好的外观、感觉和用户体验。有许多UI组件库,例如NativeBaseReact Native Elements,通常提供了许多预定义且可自定义的组件。

这些都是值得一看的,但出于我们的目的,让我们探索如何组合自己应用程序的样式和布局。

正如我们已经看到的,React Native提供了一个style属性,该属性允许我们将自定义样式应用于应用程序中的任何JSX元素。样式名称和值与CSS的样式名称和值匹配,除了名称使用camelCase编写外,例如lineHeightbackgroundColor。让我们更新/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 NativeStyleSheet库来帮助组织和重用我们的样式。

首先,我们需要将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 ComponentsEmotion。我认为这些提供了更简洁的语法,与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 NativeExpo团队推荐的路由解决方案。最重要的是,它使实现带有平台特定的外观通用路由模式变得非常简单。

首先,让我们首先在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中创建一个新文件,用作我们应用程序路由的根目录。我们将从导入初始的reactreact-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 NavigationcreateBottomTabNavigator,在这三个屏幕之间创建一个标签导航器,定义应在我们的导航中显示哪些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 NativeButton依赖项:

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-6navigationOptions中设置标题会将其添加到顶部导航栏

Icons

目前,我们的导航功能已完成,但缺少可视化组件以使用户使用更友好。值得庆幸的是,Expo使在我们的应用程序中包含图标变得异常容易。我们可以搜索Expo提供的所有图标expo.github.io/vector-icons。包括许多图标集,例如Ant DesignIoniconsFont AwesomeEntypoFoundationMaterial图标和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的数据。

如果有理解不到位的地方,欢迎大家纠错。如果觉得还可以,麻烦您点赞收藏或者分享一下,希望可以帮到更多人。

猜你喜欢

转载自blog.csdn.net/code_maomao/article/details/110218190