React Native 与 HTML 组件及样式对比指南
目录
基础组件对比
容器组件
| HTML | React Native | 说明 |
|---|---|---|
<div> | <View> | 基础容器组件,用于布局 |
<section> | <View> | 语义化容器,RN中都用View |
<article> | <View> | 文章容器,RN中都用View |
<header> | <View> | 头部容器,RN中都用View |
<footer> | <View> | 底部容器,RN中都用View |
<main> | <View> | 主要内容容器,RN中都用View |
文本组件
| HTML | React Native | 说明 |
|---|---|---|
<p> | <Text> | 段落文本 |
<span> | <Text> | 行内文本 |
<h1> - <h6> | <Text> | 标题文本,通过样式区分 |
<label> | <Text> | 标签文本 |
<strong> | <Text> | 粗体文本,通过fontWeight样式 |
<em> | <Text> | 斜体文本,通过fontStyle样式 |
表单组件
| HTML | React Native | 说明 |
|---|---|---|
<input> | <TextInput> | 文本输入框 |
<button> | <TouchableOpacity> / <Pressable> | 按钮组件 |
<select> | <Picker> | 选择器(需要@react-native-picker/picker) |
<textarea> | <TextInput multiline> | 多行文本输入 |
<checkbox> | <CheckBox> | 复选框(需要第三方库) |
<radio> | <RadioButton> | 单选框(需要第三方库) |
图片和媒体
| HTML | React Native | 说明 |
|---|---|---|
<img> | <Image> | 图片组件 |
<video> | <Video> | 视频组件(需要react-native-video) |
<audio> | <Sound> | 音频组件(需要react-native-sound) |
列表组件
| HTML | React Native | 说明 |
|---|---|---|
<ul> | <FlatList> / <ScrollView> | 列表组件 |
<ol> | <FlatList> / <ScrollView> | 有序列表 |
<li> | <View> | 列表项,用View包装 |
<table> | <ScrollView> | 表格,用ScrollView包装 |
FlatList:支持下拉刷新加载,但内部结构复杂时不好配置数据
<FlatList
data={dataArray}
renderItem={({ item }) => <ItemComponent item={item} />}
keyExtractor={(item) => item.id}
/>
ScrollView:一次性渲染,数据量大时影响性能,但内部可以嵌套复杂的结构
<ScrollView>
<View style={styles.header}>
<Text>头部内容</Text>
</View>
<View style={styles.content}>
<Text>主要内容</Text>
<View style={styles.grid}>
<View style={styles.gridItem} />
<View style={styles.gridItem} />
</View>
</View>
<View style={styles.footer}>
<Text>底部内容</Text>
</View>
</ScrollView>
样式属性对比
盒模型属性
内边距 (Padding)
HTML/CSS:
/* 简写方式 */
padding: 10px; /* 四个方向都是10px */
padding: 10px 20px; /* 上下10px,左右20px */
padding: 10px 20px 15px; /* 上10px,左右20px,下15px */
padding: 10px 20px 15px 25px; /* 上右下左 */
/* 单独设置 */
padding-top: 10px;
padding-right: 20px;
padding-bottom: 15px;
padding-left: 25px;
React Native:
// 简写方式(部分支持)
padding: 10, // 四个方向都是10
paddingHorizontal: 20, // 左右20
paddingVertical: 10, // 上下10
// 单独设置(必须)
paddingTop: 10,
paddingRight: 20,
paddingBottom: 15,
paddingLeft: 25,
外边距 (Margin)
HTML/CSS:
/* 简写方式 */
margin: 10px; /* 四个方向都是10px */
margin: 10px 20px; /* 上下10px,左右20px */
margin: 10px 20px 15px; /* 上10px,左右20px,下15px */
margin: 10px 20px 15px 25px; /* 上右下左 */
/* 单独设置 */
margin-top: 10px;
margin-right: 20px;
margin-bottom: 15px;
margin-left: 25px;
React Native:
// 简写方式(部分支持)
margin: 10, // 四个方向都是10
marginHorizontal: 20, // 左右20
marginVertical: 10, // 上下10
// 单独设置(必须)
marginTop: 10,
marginRight: 20,
marginBottom: 15,
marginLeft: 25,
边框 (Border)
HTML/CSS:
/* 简写方式 */
border: 2px solid #000; /* 宽度、样式、颜色 */
border: 2px solid #000 5px; /* 宽度、样式、颜色、圆角 */
/* 单独设置 */
border-width: 2px;
border-style: solid;
border-color: #000;
border-radius: 5px;
/* 单独方向 */
border-top: 2px solid #000;
border-right: 2px solid #000;
border-bottom: 2px solid #000;
border-left: 2px solid #000;
React Native:
// 简写方式(不支持)
// 必须单独设置每个属性
// 单独设置
borderWidth: 2,
borderStyle: 'solid', // 只支持 'solid'
borderColor: '#000',
borderRadius: 5,
// 单独方向
borderTopWidth: 2,
borderRightWidth: 2,
borderBottomWidth: 2,
borderLeftWidth: 2,
borderTopColor: '#000',
borderRightColor: '#000',
borderBottomColor: '#000',
borderLeftColor: '#000',
尺寸属性
| HTML/CSS | React Native | 说明 |
|---|---|---|
width: 100px | width: 100 | 宽度 |
height: 200px | height: 200 | 高度 |
min-width: 100px | minWidth: 100 | 最小宽度 |
max-width: 300px | maxWidth: 300 | 最大宽度 |
min-height: 100px | minHeight: 100 | 最小高度 |
max-height: 300px | maxHeight: 300 | 最大高度 |
字体属性
| HTML/CSS | React Native | 说明 |
|---|---|---|
font-size: 16px | fontSize: 16 | 字体大小 |
font-weight: bold | fontWeight: 'bold' | 字体粗细 |
font-style: italic | fontStyle: 'italic' | 字体样式 |
font-family: Arial | fontFamily: 'Arial' | 字体族 |
line-height: 1.5 | lineHeight: 24 | 行高(具体数值) |
text-align: center | textAlign: 'center' | 文本对齐 |
text-decoration: underline | textDecorationLine: 'underline' | 文本装饰 |
颜色和背景
| HTML/CSS | React Native | 说明 |
|---|---|---|
color: #ff0000 | color: '#ff0000' | 文字颜色 |
background-color: #000 | backgroundColor: '#000' | 背景色 |
background-image: url() | backgroundImage: 'url()' | 背景图片(有限支持) |
opacity: 0.5 | opacity: 0.5 | 透明度 |
定位和布局
| HTML/CSS | React Native | 说明 |
|---|---|---|
position: relative | position: 'relative' | 定位方式 |
position: absolute | position: 'absolute' | 绝对定位 |
top: 10px | top: 10 | 顶部偏移 |
left: 20px | left: 20 | 左侧偏移 |
z-index: 100 | zIndex: 100 | (仅iOS)elevation(android) |
display: flex | display: 'flex' | 弹性布局(默认) |
display: none | display: 'none' | 隐藏元素 |
布局系统对比
Flexbox 布局
HTML/CSS:
.container {
display: flex;
flex-direction: row; /* row | row-reverse | column | column-reverse */
justify-content: center; /* flex-start | flex-end | center | space-between | space-around */
align-items: center; /* flex-start | flex-end | center | baseline | stretch */
flex-wrap: wrap; /* nowrap | wrap | wrap-reverse */
}
.item {
flex: 1; /* flex-grow: 1, flex-shrink: 1, flex-basis: 0% */
flex-grow: 1; /* 增长比例 */
flex-shrink: 1; /* 收缩比例 */
flex-basis: 100px; /* 基础尺寸 */
}
React Native:
const styles = StyleSheet.create({
container: {
flexDirection: 'row', // 'row' | 'row-reverse' | 'column' | 'column-reverse'
justifyContent: 'center', // 'flex-start' | 'flex-end' | 'center' | 'space-between' | 'space-around' | 'space-evenly'
alignItems: 'center', // 'flex-start' | 'flex-end' | 'center' | 'baseline' | 'stretch'
flexWrap: 'wrap', // 'nowrap' | 'wrap' | 'wrap-reverse'
},
item: {
flex: 1, // flexGrow: 1, flexShrink: 1, flexBasis: 0
flexGrow: 1, // 增长比例
flexShrink: 1, // 收缩比例
flexBasis: 100, // 基础尺寸
}
});
Grid 布局
HTML/CSS:
.container {
display: grid;
grid-template-columns: 1fr 1fr 1fr;
grid-template-rows: auto;
grid-gap: 20px;
grid-template-areas:
"header header header"
"sidebar main aside"
"footer footer footer";
}
.item {
grid-area: main;
grid-column: 1 / 3;
grid-row: 2 / 4;
}
React Native:
// RN不支持Grid布局,需要用Flexbox模拟
const styles = StyleSheet.create({
container: {
flexDirection: 'row',
flexWrap: 'wrap',
},
item: {
width: '33.33%', // 模拟3列布局
padding: 10,
}
});
常用开发场景对比
1. 卡片组件
HTML/CSS:
<div class="card">
<img src="avatar.jpg" alt="Avatar" class="card-avatar">
<div class="card-content">
<h3 class="card-title">Card Title</h3>
<p class="card-description">Card description text</p>
</div>
</div>
.card {
display: flex;
padding: 16px;
margin: 8px;
border: 1px solid #e0e0e0;
border-radius: 8px;
box-shadow: 0 2px 4px rgba(0,0,0,0.1);
background: white;
}
.card-avatar {
width: 60px;
height: 60px;
border-radius: 30px;
margin-right: 16px;
}
.card-content {
flex: 1;
}
.card-title {
margin: 0 0 8px 0;
font-size: 18px;
font-weight: bold;
}
.card-description {
margin: 0;
color: #666;
line-height: 1.4;
}
React Native:
import React from 'react';
import { View, Text, Image, StyleSheet } from 'react-native';
const Card = () => (
<View style={styles.card}>
<Image
source={{ uri: 'avatar.jpg' }}
style={styles.cardAvatar}
/>
<View style={styles.cardContent}>
<Text style={styles.cardTitle}>Card Title</Text>
<Text style={styles.cardDescription}>Card description text</Text>
</View>
</View>
);
const styles = StyleSheet.create({
card: {
flexDirection: 'row',
padding: 16,
margin: 8,
borderWidth: 1,
borderColor: '#e0e0e0',
borderRadius: 8,
shadowColor: '#000',
shadowOffset: { width: 0, height: 2 },
shadowOpacity: 0.1,
shadowRadius: 4,
elevation: 3, // Android阴影
backgroundColor: 'white',
},
cardAvatar: {
width: 60,
height: 60,
borderRadius: 30,
marginRight: 16,
},
cardContent: {
flex: 1,
},
cardTitle: {
marginBottom: 8,
fontSize: 18,
fontWeight: 'bold',
},
cardDescription: {
color: '#666',
lineHeight: 20,
},
});
2. 按钮组件
HTML/CSS:
<button class="btn btn-primary">Primary Button</button>
<button class="btn btn-secondary">Secondary Button</button>
.btn {
padding: 12px 24px;
border: none;
border-radius: 6px;
font-size: 16px;
font-weight: 500;
cursor: pointer;
transition: all 0.2s ease;
}
.btn-primary {
background-color: #007bff;
color: white;
}
.btn-primary:hover {
background-color: #0056b3;
}
.btn-secondary {
background-color: #6c757d;
color: white;
}
.btn-secondary:hover {
background-color: #545b62;
}
React Native:
import React from 'react';
import { TouchableOpacity, Text, StyleSheet } from 'react-native';
const Button = ({ title, variant = 'primary', onPress }) => (
<TouchableOpacity
style={[styles.btn, styles[`btn${variant.charAt(0).toUpperCase() + variant.slice(1)}`]}
onPress={onPress}
activeOpacity={0.8}
>
<Text style={[styles.btnText, styles[`btnText${variant.charAt(0).toUpperCase() + variant.slice(1)}`]}>
{title}
</Text>
</TouchableOpacity>
);
const styles = StyleSheet.create({
btn: {
paddingVertical: 12,
paddingHorizontal: 24,
borderRadius: 6,
alignItems: 'center',
justifyContent: 'center',
},
btnPrimary: {
backgroundColor: '#007bff',
},
btnSecondary: {
backgroundColor: '#6c757d',
},
btnText: {
fontSize: 16,
fontWeight: '500',
},
btnTextPrimary: {
color: 'white',
},
btnTextSecondary: {
color: 'white',
},
});
3. 列表组件
HTML/CSS:
<ul class="list">
<li class="list-item">
<div class="item-content">
<h4>Item Title 1</h4>
<p>Item description 1</p>
</div>
<button class="item-action">Action</button>
</li>
<li class="list-item">
<div class="item-content">
<h4>Item Title 2</h4>
<p>Item description 2</p>
</div>
<button class="item-action">Action</button>
</li>
</ul>
.list {
list-style: none;
padding: 0;
margin: 0;
}
.list-item {
display: flex;
justify-content: space-between;
align-items: center;
padding: 16px;
border-bottom: 1px solid #e0e0e0;
}
.list-item:last-child {
border-bottom: none;
}
.item-content {
flex: 1;
}
.item-content h4 {
margin: 0 0 4px 0;
font-size: 16px;
font-weight: 500;
}
.item-content p {
margin: 0;
color: #666;
font-size: 14px;
}
.item-action {
padding: 8px 16px;
background-color: #007bff;
color: white;
border: none;
border-radius: 4px;
font-size: 14px;
}
React Native:
import React from 'react';
import { View, Text, TouchableOpacity, StyleSheet, FlatList } from 'react-native';
const ListItem = ({ item, onAction }) => (
<View style={styles.listItem}>
<View style={styles.itemContent}>
<Text style={styles.itemTitle}>{item.title}</Text>
<Text style={styles.itemDescription}>{item.description}</Text>
</View>
<TouchableOpacity style={styles.itemAction} onPress={() => onAction(item)}>
<Text style={styles.itemActionText}>Action</Text>
</TouchableOpacity>
</View>
);
const List = ({ data, onAction }) => (
<FlatList
data={data}
keyExtractor={(item) => item.id}
renderItem={({ item }) => <ListItem item={item} onAction={onAction} />}
ItemSeparatorComponent={() => <View style={styles.separator} />}
/>
);
const styles = StyleSheet.create({
listItem: {
flexDirection: 'row',
justifyContent: 'space-between',
alignItems: 'center',
padding: 16,
},
itemContent: {
flex: 1,
},
itemTitle: {
fontSize: 16,
fontWeight: '500',
marginBottom: 4,
},
itemDescription: {
color: '#666',
fontSize: 14,
},
itemAction: {
paddingVertical: 8,
paddingHorizontal: 16,
backgroundColor: '#007bff',
borderRadius: 4,
},
itemActionText: {
color: 'white',
fontSize: 14,
},
separator: {
height: 1,
backgroundColor: '#e0e0e0',
},
});
4. 表单组件
HTML/CSS:
<form class="form">
<div class="form-group">
<label for="username">Username</label>
<input type="text" id="username" class="form-input" placeholder="Enter username">
</div>
<div class="form-group">
<label for="password">Password</label>
<input type="password" id="password" class="form-input" placeholder="Enter password">
</div>
<button type="submit" class="form-submit">Submit</button>
</form>
.form {
max-width: 400px;
margin: 0 auto;
padding: 20px;
}
.form-group {
margin-bottom: 20px;
}
.form-group label {
display: block;
margin-bottom: 8px;
font-weight: 500;
color: #333;
}
.form-input {
width: 100%;
padding: 12px;
border: 1px solid #ddd;
border-radius: 6px;
font-size: 16px;
box-sizing: border-box;
}
.form-input:focus {
outline: none;
border-color: #007bff;
box-shadow: 0 0 0 3px rgba(0,123,255,0.1);
}
.form-submit {
width: 100%;
padding: 12px;
background-color: #007bff;
color: white;
border: none;
border-radius: 6px;
font-size: 16px;
font-weight: 500;
cursor: pointer;
}
.form-submit:hover {
background-color: #0056b3;
}
React Native:
import React, { useState } from 'react';
import { View, Text, TextInput, TouchableOpacity, StyleSheet } from 'react-native';
const Form = () => {
const [username, setUsername] = useState('');
const [password, setPassword] = useState('');
const handleSubmit = () => {
// 处理提交逻辑
console.log('Submit:', { username, password });
};
return (
<View style={styles.form}>
<View style={styles.formGroup}>
<Text style={styles.label}>Username</Text>
<TextInput
style={styles.input}
value={username}
onChangeText={setUsername}
placeholder="Enter username"
placeholderTextColor="#999"
/>
</View>
<View style={styles.formGroup}>
<Text style={styles.label}>Password</Text>
<TextInput
style={styles.input}
value={password}
onChangeText={setPassword}
placeholder="Enter password"
placeholderTextColor="#999"
secureTextEntry
/>
</View>
<TouchableOpacity style={styles.submitButton} onPress={handleSubmit}>
<Text style={styles.submitButtonText}>Submit</Text>
</TouchableOpacity>
</View>
);
};
const styles = StyleSheet.create({
form: {
maxWidth: 400,
alignSelf: 'center',
padding: 20,
},
formGroup: {
marginBottom: 20,
},
label: {
marginBottom: 8,
fontWeight: '500',
color: '#333',
},
input: {
width: '100%',
paddingVertical: 12,
paddingHorizontal: 12,
borderWidth: 1,
borderColor: '#ddd',
borderRadius: 6,
fontSize: 16,
},
submitButton: {
width: '100%',
paddingVertical: 12,
backgroundColor: '#007bff',
borderRadius: 6,
alignItems: 'center',
},
submitButtonText: {
color: 'white',
fontSize: 16,
fontWeight: '500',
},
});
最佳实践建议
1. 样式组织
HTML/CSS:
- 使用CSS类名和BEM命名规范
- 利用CSS预处理器(Sass/Less)
- 使用CSS变量和自定义属性
React Native:
- 使用StyleSheet.create()提高性能
- 将样式对象分离到单独文件
- 使用主题系统管理颜色和尺寸
2. 响应式设计
HTML/CSS:
/* 媒体查询 */
@media (max-width: 768px) {
.container {
padding: 10px;
}
}
/* CSS Grid自动响应 */
.grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
}
React Native:
import { Dimensions } from 'react-native';
const { width, height } = Dimensions.get('window');
const styles = StyleSheet.create({
container: {
padding: width > 768 ? 20 : 10,
},
grid: {
flexDirection: 'row',
flexWrap: 'wrap',
},
gridItem: {
width: width > 768 ? '33.33%' : '50%',
},
});
3. 性能优化
HTML/CSS:
- 使用CSS transform和opacity进行动画
- 避免重排和重绘
- 使用CSS containment
React Native:
- 使用Animated API进行动画
- 避免在render中创建样式对象
- 使用React.memo优化组件重渲染
4. 平台适配
React Native:
import { Platform } from 'react-native';
const styles = StyleSheet.create({
container: {
...Platform.select({
ios: {
shadowColor: '#000',
shadowOffset: { width: 0, height: 2 },
shadowOpacity: 0.1,
shadowRadius: 4,
},
android: {
elevation: 3,
},
}),
},
});
总结
React Native和HTML在组件和样式方面存在显著差异:
- 组件映射: RN使用原生组件,HTML使用语义化标签
- 样式简写: HTML支持丰富的CSS简写,RN需要单独设置属性
- 布局系统: HTML支持Grid和Flexbox,RN主要使用Flexbox
- 平台差异: RN需要考虑iOS和Android的平台差异
- 性能优化: 两者都有各自的性能优化策略
理解这些差异有助于在跨平台开发中做出正确的技术选择,并编写更高效的代码。