rn_for_openharmony狗狗之家app实战-领养申请实现
领养申请表单实现要点 摘要:本文介绍了React Native领养申请表单的实现过程,主要包括: 页面结构采用Header+ScrollView+Footer布局 使用TextInput组件实现单行和多行输入框 针对不同输入类型设置键盘样式(如电话键盘) 表单包含个人信息、养宠经验和领养承诺三个部分 通过样式设计提升表单可用性(圆角、间距、标签等) 实际应用还需添加表单状态管理和验证逻辑 (149
案例开源地址:https://atomgit.com/nutpi/rn_openharmony_dogimg
表单是信任的桥梁
用户决定领养一只狗狗后,需要填写申请表。这个表单不只是收集信息,更是建立信任的过程。
领养机构需要了解申请人的情况,判断是否适合养狗。申请人通过填写表单,表达自己的诚意和准备。
这篇文章讲 AdoptFormPage 的实现,涉及到表单布局、输入框组件、表单验证等内容。
页面的导入部分
import React from 'react';
import {View, Text, ScrollView, TextInput, TouchableOpacity, StyleSheet} from 'react-native';
import {Header, Card} from '../../components';
import {useNavigation, useRoute} from '../../hooks';
import type {AdoptDog} from '../../types';
这个页面用到了 TextInput,这是 React Native 的文本输入组件,相当于 HTML 的 input 和 textarea。
其他导入和之前的页面类似:Header 做顶部导航,Card 做内容分组,useNavigation 和 useRoute 处理路由。
获取路由参数
export function AdoptFormPage() {
const {navigate} = useNavigation();
const {params} = useRoute<{dog: AdoptDog}>();
从详情页跳转过来时,带了 dog 参数。
表单页需要知道用户申请领养的是哪只狗,用于显示和提交。
页面整体结构
return (
<View style={s.container}>
<Header title="领养申请" />
<ScrollView style={s.content}>
...
</ScrollView>
<View style={s.footer}>
...
</View>
</View>
);
和详情页一样的三层结构:Header、ScrollView、footer。
表单内容可能很长,需要滚动。提交按钮固定在底部,随时可点。
显示申请的狗狗
<Card>
<Text style={s.dogName}>申请领养: {params.dog.name}</Text>
</Card>
在表单顶部显示狗狗的名字,让用户确认自己申请的是哪只。
dogName: {fontSize: 16, fontWeight: '500', color: '#D2691E', textAlign: 'center'},
用主题色显示名字,居中对齐,作为表单的"标题"。
fontWeight: '500' 是中等粗细,比普通文字稍重,但不像 ‘600’ 那么粗。
个人信息区域
<Card>
<Text style={s.sectionTitle}>个人信息</Text>
<Text style={s.label}>姓名 *</Text>
<TextInput style={s.input} placeholder="请输入您的姓名" />
<Text style={s.label}>联系电话 *</Text>
<TextInput style={s.input} placeholder="请输入联系电话" keyboardType="phone-pad" />
<Text style={s.label}>居住地址 *</Text>
<TextInput style={s.input} placeholder="请输入居住地址" />
</Card>
三个必填字段:姓名、电话、地址。
标签后面的 * 表示必填,这是表单设计的通用约定。
每个输入框都有 placeholder 提示用户该填什么。
TextInput 的基本用法
<TextInput style={s.input} placeholder="请输入您的姓名" />
style 设置输入框的样式。
placeholder 是占位文字,输入框为空时显示,用户开始输入后消失。
电话输入框的键盘类型
<TextInput
style={s.input}
placeholder="请输入联系电话"
keyboardType="phone-pad"
/>
keyboardType="phone-pad" 让弹出的键盘是数字键盘,方便输入电话号码。
常用的 keyboardType 值:
- default:默认键盘
- numeric:纯数字键盘
- phone-pad:电话键盘,有数字和 + - * #
- email-address:带 @ 和 . 的键盘
选择合适的键盘类型能提升输入效率。
输入框样式
input: {
backgroundColor: '#f5f5f5',
borderRadius: 8,
padding: 12,
fontSize: 15,
color: '#333'
},
backgroundColor: ‘#f5f5f5’ 浅灰色背景,和 Card 的白色背景区分开。
borderRadius: 8 圆角,看起来更柔和。
padding: 12 内边距,文字不贴边。
fontSize: 15 输入文字的大小。
color: ‘#333’ 输入文字的颜色。
标签样式
label: {fontSize: 14, color: '#666', marginBottom: 6, marginTop: 10},
标签用小一号的灰色字体。
marginBottom: 6 和输入框拉开一点距离。
marginTop: 10 和上一个输入框拉开距离,除了第一个标签。
区域标题样式
sectionTitle: {fontSize: 16, fontWeight: '600', color: '#333', marginBottom: 10},
区域标题比标签大一号,加粗,深色。
marginBottom: 10 和下面的内容拉开距离。
养宠经验区域
<Card>
<Text style={s.sectionTitle}>养宠经验</Text>
<TextInput
style={[s.input, s.textarea]}
placeholder="请描述您的养宠经验和家庭情况"
multiline
numberOfLines={4}
/>
</Card>
这是个多行输入框,用于填写较长的文字。
multiline 让输入框支持多行输入,相当于 HTML 的 textarea。
numberOfLines={4} 设置默认显示 4 行的高度。
style={[s.input, s.textarea]} 用数组合并两个样式。
多行输入框样式
textarea: {height: 100, textAlignVertical: 'top'},
height: 100 固定高度,比单行输入框高。
textAlignVertical: ‘top’ 让光标和文字从顶部开始。这是 Android 特有的属性,iOS 默认就是顶部对齐。
如果不加这个属性,Android 上的光标会在输入框中间,很奇怪。
领养承诺区域
<Card>
<Text style={s.sectionTitle}>领养承诺</Text>
<Text style={s.promise}>• 我承诺会善待领养的狗狗</Text>
<Text style={s.promise}>• 我承诺定期带狗狗进行健康检查</Text>
<Text style={s.promise}>• 我承诺不会遗弃狗狗</Text>
</Card>
这不是输入区域,而是展示领养承诺条款。
用 • 符号做列表项的标记,简单直观。
promise: {fontSize: 14, color: '#666', lineHeight: 26},
lineHeight: 26 让每行之间有足够的间距,阅读更舒适。
为什么要展示承诺条款
领养不是买卖,是一种责任。展示承诺条款有几个作用:
筛选作用:不认同这些条款的人可能会放弃申请。
教育作用:提醒申请人养狗需要承担的责任。
法律作用:提交申请相当于同意这些条款,有一定的约束力。
提交按钮
<View style={s.footer}>
<TouchableOpacity style={s.btn} onPress={() => navigate('AdoptDone', {name: params.dog.name})}>
<Text style={s.btnText}>提交申请</Text>
</TouchableOpacity>
</View>
点击后跳转到完成页面,传递狗狗的名字用于显示。
footer: {backgroundColor: '#fff', padding: 16, paddingBottom: 32},
btn: {backgroundColor: '#D2691E', paddingVertical: 14, borderRadius: 8, alignItems: 'center'},
btnText: {fontSize: 16, fontWeight: '600', color: '#fff'},
和详情页的按钮样式一致,保持视觉统一。
表单状态管理
当前代码没有管理输入状态,实际应该这样:
const [form, setForm] = useState({
name: '',
phone: '',
address: '',
experience: '',
});
const updateField = (field: string, value: string) => {
setForm({...form, [field]: value});
};
用一个对象存储所有字段的值。
updateField 是通用的更新函数,[field] 是计算属性名,可以动态指定要更新的字段。
<TextInput
style={s.input}
placeholder="请输入您的姓名"
value={form.name}
onChangeText={(text) => updateField('name', text)}
/>
value 绑定状态值,让输入框显示当前值。
onChangeText 在用户输入时触发,更新状态。
这就是 React 的受控组件模式,状态是唯一的数据源。
表单验证
提交前要检查必填字段:
const validateForm = (): boolean => {
if (!form.name.trim()) {
Alert.alert('提示', '请输入姓名');
return false;
}
if (!form.phone.trim()) {
Alert.alert('提示', '请输入联系电话');
return false;
}
if (!form.address.trim()) {
Alert.alert('提示', '请输入居住地址');
return false;
}
return true;
};
const handleSubmit = () => {
if (!validateForm()) return;
navigate('AdoptDone', {name: params.dog.name});
};
trim() 去掉首尾空格,防止用户只输入空格。
验证失败时弹窗提示,返回 false 阻止提交。
电话号码格式验证
const isValidPhone = (phone: string): boolean => {
// 简单的手机号验证:11位数字,以1开头
return /^1\d{10}$/.test(phone);
};
if (!isValidPhone(form.phone)) {
Alert.alert('提示', '请输入正确的手机号码');
return false;
}
用正则表达式验证手机号格式。
^1 以 1 开头,\d{10} 后面跟 10 位数字,$ 结尾。
这是简化的验证,实际可能需要更复杂的规则。
输入框焦点管理
填完一个字段后,自动跳到下一个:
const phoneRef = useRef<TextInput>(null);
const addressRef = useRef<TextInput>(null);
<TextInput
placeholder="请输入您的姓名"
returnKeyType="next"
onSubmitEditing={() => phoneRef.current?.focus()}
/>
<TextInput
ref={phoneRef}
placeholder="请输入联系电话"
returnKeyType="next"
onSubmitEditing={() => addressRef.current?.focus()}
/>
<TextInput
ref={addressRef}
placeholder="请输入居住地址"
returnKeyType="done"
/>
ref 获取输入框的引用。
returnKeyType 设置键盘回车键的文字,“next” 显示"下一项",“done” 显示"完成"。
onSubmitEditing 在用户按回车时触发,调用下一个输入框的 focus 方法。
这样用户可以连续填写,不用手动点击每个输入框。
键盘遮挡问题
输入框在屏幕下方时,弹出的键盘可能会遮挡它。
解决方案是用 KeyboardAvoidingView:
import {KeyboardAvoidingView, Platform} from 'react-native';
<KeyboardAvoidingView
style={s.container}
behavior={Platform.OS === 'ios' ? 'padding' : 'height'}
>
...
</KeyboardAvoidingView>
KeyboardAvoidingView 会在键盘弹出时自动调整布局,让输入框不被遮挡。
behavior 在 iOS 和 Android 上需要不同的值才能正常工作。
提交状态处理
防止重复提交:
const [submitting, setSubmitting] = useState(false);
const handleSubmit = async () => {
if (submitting) return;
if (!validateForm()) return;
setSubmitting(true);
try {
await api.submitAdoptForm({
dogId: params.dog.id,
...form,
});
navigate('AdoptDone', {name: params.dog.name});
} catch (e) {
Alert.alert('提交失败', '请稍后重试');
} finally {
setSubmitting(false);
}
};
submitting 状态在提交过程中为 true,防止用户重复点击。
提交按钮也要显示加载状态:
<TouchableOpacity
style={[s.btn, submitting && s.btnDisabled]}
onPress={handleSubmit}
disabled={submitting}
>
<Text style={s.btnText}>{submitting ? '提交中...' : '提交申请'}</Text>
</TouchableOpacity>
页面容器样式
container: {flex: 1, backgroundColor: '#f5f5f5'},
content: {flex: 1},
灰色背景,和其他页面保持一致。
content 的 flex: 1 让 ScrollView 占据中间的所有空间。
小结
领养申请页面的实现要点:
- TextInput 组件:单行输入用默认配置,多行输入加 multiline
- 键盘类型:根据输入内容选择合适的 keyboardType
- 表单状态:用 useState 管理所有字段的值
- 表单验证:提交前检查必填字段和格式
- 焦点管理:用 ref 和 onSubmitEditing 实现连续输入
- 键盘遮挡:用 KeyboardAvoidingView 解决
表单是用户和系统交互的重要方式,好的表单设计能提升用户体验和数据质量。
下一篇讲领养完成页面,给用户一个温暖的反馈。
欢迎加入开源鸿蒙跨平台社区:https://openharmonycrossplatform.csdn.net
更多推荐



所有评论(0)