Skip to content

superlldw/collect-app

Repository files navigation

Expo App + Express.js

目录结构规范(严格遵循)

当前仓库是一个 monorepo(基于 pnpm 的 workspace)

  • Expo 代码在 client 目录,Express.js 代码在 server 目录
  • 本模板默认无 Tab Bar,可按需改造

├── client/ # React Native 前端代码 │ ├── app/ # Expo Router 路由目录(仅路由配置) │ │ ├── _layout.tsx # 根布局文件(必需,务必阅读) │ │ └── index.tsx # 首页 │ ├── screens/ # 页面实现目录(与 app/ 路由对应) │ │ └── demo/ # 示例页面 │ │ └── index.tsx │ ├── components/ # 可复用组件 │ │ └── Screen.tsx # 页面容器组件(必用) │ ├── hooks/ # 自定义 Hooks │ ├── contexts/ # React Context 代码 │ ├── utils/ # 工具函数 │ ├── assets/ # 静态资源 | └── package.json # Expo 应用 package.json ├── server/ # 服务端代码根目录 (Express.js) | ├── src/ │ │ └── index.ts # 服务端入口文件 | └── package.json # 服务端 package.json ├── package.json ├── .cozeproj # 预置脚手架脚本(禁止修改) └── .coze # 配置文件(禁止修改)

样式方案

基于 tailwindcss 进行样式开发(底层基于 Uniwind)

写法示例:

<View className="flex-1 bg-white dark:bg-gray-900 p-4"></View>
<Text
  className="text-lg font-bold text-gray-900 dark:text-white"
  selectionColorClassName="accent-blue-500"
>
  Hello World
</Text>

Uniwind 官方文档:https://docs.uniwind.dev/llms.txt

如何进行静态校验(TSC + ESLint)

# 对 client 和 server 目录同时进行校验
pnpm -w lint:all

# 对 client 目录进行校验
pnpm -w lint:client

# 对 server 目录进行校验
pnpm -w lint:server

如何修改主题模式(跟随系统、固定暗色、固定亮色)

默认为跟随系统,如果用户明确指定为“暗色”或“亮色”,需要修改 client/components/ColorSchemeUpdater.tsxDEFAULT_THEME 变量为合适的值

如何定制主题 design tokens

当前项目的设计系统基于 tailwindcss 实现,核心入口文件为 client/global.css,如果需要定制主题,应该阅读并修改 client/global.css 文件

路由及 Tab Bar 实现规范

方案一:无 Tab Bar(Stack 导航)

适用于线性流程应用,采用简化的目录结构:

client/app/
├── _layout.tsx         # 根布局(Stack 导航配置)
├── index.tsx           # 应用入口
├── detail.tsx          # 详情页(通过 params 传递数据)
└── +not-found.tsx      # 404 页面

根布局配置 client/app/_layout.tsx

以下仅为代码片段供写法参考

<Stack screenOptions={{ headerShown: false }}>
  <Stack.Screen name="index" />
  <Stack.Screen name="detail" />
</Stack>

应用入口 client/app/index.tsx

export { default } from "@/screens/home";

禁止事项:无 Tab Bar 场景下,不得创建 (tabs) 目录。

方案二:有 Tab Bar(Tabs 导航)

采用路由分组实现底部导航栏:

client/app/
├── _layout.tsx              # 根布局
├── (tabs)/
│   ├── _layout.tsx          # Tab 导航配置
│   ├── index.tsx            # 默认 Tab(必须存在)
│   ├── discover.tsx         # 发现页
│   └── profile.tsx          # 个人中心
├── detail.tsx               # Tab 外的独立页面(通过 params 传递数据)
└── +not-found.tsx

⚠️ [CRITICAL]app/index.tsx 优先级高于 (tabs)/index.tsx,会导致首页无 Tab Bar。当有(tabs)/index.tsx时必须删除 app/index.tsx

根布局配置 client/app/_layout.tsx

以下仅为代码片段供写法参考

<Stack screenOptions={{ headerShown: false }}>
  <Stack.Screen name="(tabs)" />
  <Stack.Screen name="detail" />
</Stack>

应用入口 client/app/(tabs)/index.tsx

export { default } from "@/screens/home";

Tab 布局配置 client/app/(tabs)/_layout.tsx

import { Tabs } from 'expo-router';
import { Platform } from 'react-native';
import { useSafeAreaInsets } from 'react-native-safe-area-context';
import { FontAwesome6 } from '@expo/vector-icons';
import { useCSSVariable } from 'uniwind';

export default function TabLayout() {
  const insets = useSafeAreaInsets();
  const [background, muted, accent, border] = useCSSVariable([
    '--color-background',
    '--color-muted',
    '--color-accent',
    '--color-border',
  ]) as string[];

  return (
    <Tabs
      screenOptions={{
        headerShown: false,
        tabBarStyle: {
          backgroundColor: background,
          borderTopWidth: 1,
          borderTopColor: border,
          // 通过固定宽度 55 来修正 Web 上的表现
          height: Platform.OS === 'web' ? 55 : 50 + insets.bottom,
        },
        tabBarActiveTintColor: accent,
        tabBarInactiveTintColor: muted,
      }}
    >
      {/* name 必须与文件名完全一致 */}
      <Tabs.Screen
        name="index"
        options={{
          title: '首页',
          tabBarIcon: ({ color }) => (
            <FontAwesome6 name="house" size={20} color={color} />
          ),
        }}
      />
      <Tabs.Screen
        name="discover"
        options={{
          title: '发现',
          tabBarIcon: ({ color }) => (
            <FontAwesome6 name="compass" size={20} color={color} />
          ),
        }}
      />
      <Tabs.Screen
        name="profile"
        options={{
          title: '我的',
          tabBarIcon: ({ color }) => (
            <FontAwesome6 name="user" size={20} color={color} />
          ),
        }}
      />
    </Tabs>
  );
}

Tab 页面文件 client/app/(tabs)/index.tsx

export { default } from "@/screens/home";

注意事项

在改动 client/app/_layout.tsx 前,必须先阅读该文件,再进行修改操作

以下是需要保留的重要逻辑

  • 保留 global.css 引入(tailwindcss 生效的关键)
  • 保留 Provider 的使用

依赖管理与模块导入规范

依赖安装

禁止使用 npmyarn,按目录区分安装命令:

目录 安装命令 说明
client/ npx expo install <package> Expo 会自动选择与 SDK 兼容的版本
server/ pnpm add <package> 使用 pnpm 管理后端依赖
# client 目录(Expo 项目)
cd client && npx expo install expo-camera expo-image-picker

# server 目录(Express 项目)
cd server && pnpm add axios cors

网络问题处理npx expo install 可能因网络原因失败,失败时重试 2 次,仍失败则改用 pnpm add 安装

Expo 开发规范

路径别名

Expo 配置了 @/ 路径别名指向 client/ 目录:

// 正确
import { Screen } from '@/components/Screen';

// 避免相对路径
import { Screen } from '../../../components/Screen';

本地开发

coze dev:用来首次启动前后端服务,也可以用来重启前后端服务(该命令会先尝试杀掉占用端口的进程,再启动服务)

About

拍照+语音+文字关联采集应用

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors