React Native基础

目录

一、创建项目

二、组件介绍

2.1、Text、View和Image组件

2.2、文件式导航(Link)

2.3、堆栈导航(Stack)

2.4、浅色与深色主题

2.5、主题化UI组件

2.6、路由分组与嵌套布局

2.7、Pressable组件

2.8、标签栏导航(Tabs)

2.9、安全区域适配(SafeAreaView)

一、创建项目

Expo官网:Expo Documentation (中文官网:教程:介绍 - Expo 中文网)
创建一个文件夹,在VS Code的终端下输入命令:

**npx create-expo-app@latest --template blank ./**创建出一个空白模板的app

在英文官网首页点击Set up your environment - Expo Documentation

设置路由:Install Expo Router - Expo Documentation

二、组件介绍

2.1、Text、View和Image组件

效果展示:

javascript 复制代码
import { StyleSheet, Text, View, Image } from "react-native";
import Logo from "../assets/system.png";
export default function Page() {
  return (
    <View style={styles.container}>
      {/* 文本 */}
      <Text style={styles.title}>The Number 1</Text>
      {/* 内联样式 */}
      <Text style={{ marginTop: 10 }}>Welcome to Expo</Text>
      {/* 外部样式+内联样式 */}
      <Text style={[styles.title,{color:'gold'}]}>Reading this app</Text>
      {/* 图片 */}
      <Image style={styles.img} source={Logo} />
    </View>
  );
}
const styles = StyleSheet.create({
  container: {
    flex: 1,
    backgroundColor: "skyblue",
    alignItems: "center",
    justifyContent: "center",
  },
  title: {
    fontSize: 20,
    fontWeight: "bold",
  },
  img: {
    borderRadius: "50%",
    marginVertical: 10,
  },
});

2.2、文件式导航(Link)

javascript 复制代码
import { Link } from "expo-router";
{/* 跳转 相当于HTML中的a标签 */}
<Link href="/about">跳转到about页面</Link>

2.3、堆栈导航(Stack)

为了产生页面的返回键和页面标题,前提:在app文件夹下建立_layout.jsx文件。

javascript 复制代码
import { Stack } from "expo-router";
const RootLayout = () => {
  return (
    <Stack
      screenOptions={{
        headerStyle: { backgroundColor: "#ddd" },
        headerTintColor: "#333",
      }}
    >
      <Stack.Screen name="index" options={{title: "Home"}}/>
      <Stack.Screen name="about" options={{title: "About"}}/>
      <Stack.Screen name="contact" options={{title: "Contact"}}/>
    </Stack>
  );
};
export default RootLayout;
// 如果第一步安装路由启动失败,加上_layout.jsx这个文件
// 可以重新安装依赖:rm -rf node_modules package-lock.json  npm install
// 想在web端查看页面:npx expo install react-dom react-native-web
// 再重新运行:npx expo start

2.4、浅色与深色主题

javascript 复制代码
import { useColorScheme } from "react-native";
import { Colors } from "../constants/Color";
import { StatusBar } from "expo-status-bar";
const RootLayout = () => {
  const colorScheme = useColorScheme();
  const theme = Colors[colorScheme] ?? Colors.light;
  return (
    <>
      <StatusBar value="auto" />
    </>
  );
};

2.5、主题化UI组件

以View为例:

javascript 复制代码
import { View, useColorScheme } from "react-native";
import {Colors} from "../constants/Color";
const ThemeView = ({ style, children, ...props }) => {
  const colorScheme = useColorScheme();
  const theme = Colors[colorScheme] ?? Colors.light;
  return (
    <View style={[style, { backgroundColor: theme.background }]} {...props}>
      {children}
    </View>
  );
};
export default ThemeView;

其实可以自己选组件库:

React Native Elements、 React Native Paper和UI Kitten的文档如下(兼容IOS和安卓,后面两个可以搭配使用):

Overview | React Native Elements

ActivityIndicator | React Native Paper

UI Kitten - React Native Components

2.6、路由分组与嵌套布局

路由分组:将功能相关的路由归类,统一管理配置(如认证路由和主应用路由分离)

在app文件夹下再建一个文件夹,命名时用()括起来,此时页面title会变为"(auth/login)",此时想要取消页面的Header显示,则需要在(auth)文件夹下再建立一个_layout.jsx

javascript 复制代码
import { Stack } from "expo-router";
import { StatusBar } from "expo-status-bar";
const AuthLayout = () => {
  return (
    <>
      <StatusBar value="auto" />
      <Stack
        screenOptions={{
          headerShown: false,
          animation: "none",
        }}
      ></Stack>
    </>
  );
};
export default AuthLayout;

在RootLayout.jsx里

javascript 复制代码
<Stack.Screen name="(auth)" options={{headerShown: false}}/>

或者使用createNativeStackNavigator 分组

javascript 复制代码
// App.js
import { createNativeStackNavigator } from '@react-navigation/native-stack';
const AuthStack = createNativeStackNavigator();
const MainStack = createNativeStackNavigator();
function AuthGroup() {
  return (
    <AuthStack.Navigator>
      <AuthStack.Screen name="Login" component={LoginScreen} />
      <AuthStack.Screen name="Register" component={RegisterScreen} />
    </AuthStack.Navigator>
  );
}
function MainGroup() {
  return (
    <MainStack.Navigator>
      <MainStack.Screen name="Home" component={HomeScreen} />
      <MainStack.Screen name="Profile" component={ProfileScreen} />
    </MainStack.Navigator>
  );
}
// 根导航器整合分组
const RootStack = createNativeStackNavigator();
function App() {
  return (
    <NavigationContainer>
      <RootStack.Navigator>
        <RootStack.Screen 
          name="Auth" 
          component={AuthGroup} 
          options={{ headerShown: false }}
        />
        <RootStack.Screen 
          name="Main" 
          component={MainGroup} 
          options={{ headerShown: false }}
        />
      </RootStack.Navigator>
    </NavigationContainer>
  );
}

拓展:

  1. 路由参数传递
javascript 复制代码
// 父路由传递参数给子路由
<Stack.Screen 
  name="Profile" 
  component={ProfileScreen}
  initialParams={{ userId: 123 }}
/>

// 子路由获取参数
function ProfileScreen({ route }) {
  const { userId } = route.params;
}
  1. 统一导航选项
javascript 复制代码
// 分组统一配置
<Stack.Navigator
  screenOptions={{
    headerStyle: { backgroundColor: '#4CAF50' },
    headerTintColor: 'white'
  }}
>
  {/* 所有子路由继承此样式 */}
</Stack.Navigator>

3、动态隐藏Header:headerShown: false

2.7、Pressable组件

用于检测各种按压交互(点击、长按等)

自定义组件ThemeBtn.jsx:

javascript 复制代码
import { StyleSheet, Pressable } from "react-native";
const ThemeBtn = ({ style, ...props }) => {
  return (
    <Pressable
      style={({ pressed }) => [
        styles.button,
        pressed && styles.buttonPressed,
        style,
      ]}
      {...props}
    />
  );
};
export default ThemeBtn;
const styles = StyleSheet.create({
  button: {
    padding: 18,
    marginVertical: 10,
    borderRadius: 6,
    backgroundColor: "#6849a7",
  },
  buttonPressed: {
    opacity: 0.5,
  },
});

父组件引用

javascript 复制代码
import ThemeBtn from "../../components/ThemeBtn";
const Login = () => {
  const handleSubmit = () => {
    console.log("submit");
  };
  return (
    <View>
      <ThemeBtn onPress={handleSubmit}>
        <Text style={{ color: "#f2f2f2", textAlign: "center" }}>Press Me</Text>
      </ThemeBtn>
    </View>
  );
};
export default Login;

列表项按压效果

javascript 复制代码
function ListItem({ item }) {
  return (
    <Pressable
      onPress={() => navigate('Detail', { id: item.id })}
      style={({ pressed }) => ({
        padding: 16,
        backgroundColor: pressed ? '#f0f0f0' : 'white',
      })}
    >
      <Text>{item.name}</Text>
    </Pressable>
  );
}

2.8、标签栏导航(Tabs)

建立(dashboard)文件夹,分别建立三个.jsx文件:profile、books、create

javascript 复制代码
import { Tabs } from "expo-router";
import { useColorScheme } from "react-native";
import { Colors } from "../../constants/Color";
// 下载图标 npm i @expo/vector-icons , 默认自带
import { Ionicons } from "@expo/vector-icons";
const DashboardLayout = () => {
  const colorScheme = useColorScheme();
  const theme = colorScheme === "dark" ? Colors.dark : Colors.light;
  return (
    <Tabs
      screenOptions={{
        headerShown: false,
        tabBarStyle: {
          backgroundColor: theme.navBackground,
          paddingTop: theme.iconColor,
          height: 90,
        },
        tabBarActiveTintColor: theme.iconColorFocused,
        tabBarInactiveTintColor: theme.iconColor,
      }}
    >
      {/* 自定义底部导航栏标题和图标 */}
      <Tabs.Screen
        name="profile"
        options={{
          title: "Profile",
          tabBarIcon: ({ focused }) => (
            <Ionicons
              name={focused ? "person" : "person-outline"}
              size={24}
              color={focused ? theme.iconColorFocused : theme.iconColor}
            />
          ),
        }}
      />
      <Tabs.Screen name="books" options={{ title: "Books" }} />
      <Tabs.Screen name="create" options={{ title: "Create" }} />
    </Tabs>
  );
};
export default DashboardLayout;

2.9、安全区域适配(SafeAreaView)

复制代码
SafeAreaView:直接包裹当前页面,但是无法灵活控制具体哪一侧需要安全边距,所以选择以下HOOk
useSafeAreaInsets() :可以手动获取安全区域的 top、bottom、left、right 值,并应用到样式中
javascript 复制代码
import { View, useColorScheme } from "react-native";
import { Colors } from "../constants/Color";
import { useSafeAreaInsets } from "react-native-safe-area-context";
const ThemeView = ({ style, safe = false, ...props }) => {
  const colorScheme = useColorScheme();
  const theme = Colors[colorScheme] ?? Colors.light;
  if (!safe)
    return (
      <View style={[style, { backgroundColor: theme.background }]} {...props} />
    );
  const insets = useSafeAreaInsets();
  return (
    <View
      style={[
        style,
        {
          backgroundColor: theme.background,
          paddingTop: insets.top,     // 避开刘海
          paddingBottom: insets.bottom, // 避开底部横条
        },
      ]}
      {...props}
    />
  );
};
export default ThemeView;
相关推荐
用户831348593069811 小时前
Vue3 v-for:常用用法与开发高频坑点
前端·javascript·vue.js
Funlang11 小时前
fun-ui 开源:把浏览器界面接回来
前端·javascript
2603_9658966211 小时前
CSS BEM 命名规范|组件化样式分层权威指南
前端·javascript·css
忆挽篱笙歌12 小时前
进程替换函数与shenll命令行解释器
前端·javascript·算法
小冯不疯12 小时前
688 / 拼多多 / 淘特三类供货链路:从采购单到应付凭证的 4 段对账
javascript
moshuying12 小时前
DeppInfer系列之 - 矩阵、注意力与 GPU:拆解 DeepGEMM 与 FlashMLA
前端·javascript·面试
Jack N13 小时前
【Strapi 系列之五】前端怎么接?Next.js + Tailwind 拉取 Strapi 数据(含代码)
开发语言·前端·javascript·strapi
来一首_We_go13 小时前
React Flow Pro 高级交互实现
前端·react.js
weedsfly14 小时前
React 不可变数据:为什么页面“明明数据变了却不更新
前端·javascript·react.js
Gizzap_Tech14 小时前
双语内容审阅台怎么做?用内容指纹保留核验记录
javascript