React Native 与 HTML 组件及样式对比指南

144 阅读9分钟

React Native 与 HTML 组件及样式对比指南

目录

基础组件对比

容器组件

HTMLReact Native说明
<div><View>基础容器组件,用于布局
<section><View>语义化容器,RN中都用View
<article><View>文章容器,RN中都用View
<header><View>头部容器,RN中都用View
<footer><View>底部容器,RN中都用View
<main><View>主要内容容器,RN中都用View

文本组件

HTMLReact Native说明
<p><Text>段落文本
<span><Text>行内文本
<h1> - <h6><Text>标题文本,通过样式区分
<label><Text>标签文本
<strong><Text>粗体文本,通过fontWeight样式
<em><Text>斜体文本,通过fontStyle样式

表单组件

HTMLReact Native说明
<input><TextInput>文本输入框
<button><TouchableOpacity> / <Pressable>按钮组件
<select><Picker>选择器(需要@react-native-picker/picker)
<textarea><TextInput multiline>多行文本输入
<checkbox><CheckBox>复选框(需要第三方库)
<radio><RadioButton>单选框(需要第三方库)

图片和媒体

HTMLReact Native说明
<img><Image>图片组件
<video><Video>视频组件(需要react-native-video)
<audio><Sound>音频组件(需要react-native-sound)

列表组件

HTMLReact 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/CSSReact Native说明
width: 100pxwidth: 100宽度
height: 200pxheight: 200高度
min-width: 100pxminWidth: 100最小宽度
max-width: 300pxmaxWidth: 300最大宽度
min-height: 100pxminHeight: 100最小高度
max-height: 300pxmaxHeight: 300最大高度

字体属性

HTML/CSSReact Native说明
font-size: 16pxfontSize: 16字体大小
font-weight: boldfontWeight: 'bold'字体粗细
font-style: italicfontStyle: 'italic'字体样式
font-family: ArialfontFamily: 'Arial'字体族
line-height: 1.5lineHeight: 24行高(具体数值)
text-align: centertextAlign: 'center'文本对齐
text-decoration: underlinetextDecorationLine: 'underline'文本装饰

颜色和背景

HTML/CSSReact Native说明
color: #ff0000color: '#ff0000'文字颜色
background-color: #000backgroundColor: '#000'背景色
background-image: url()backgroundImage: 'url()'背景图片(有限支持)
opacity: 0.5opacity: 0.5透明度

定位和布局

HTML/CSSReact Native说明
position: relativeposition: 'relative'定位方式
position: absoluteposition: 'absolute'绝对定位
top: 10pxtop: 10顶部偏移
left: 20pxleft: 20左侧偏移
z-index: 100zIndex: 100(仅iOS)elevation(android)
display: flexdisplay: 'flex'弹性布局(默认)
display: nonedisplay: '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在组件和样式方面存在显著差异:

  1. 组件映射: RN使用原生组件,HTML使用语义化标签
  2. 样式简写: HTML支持丰富的CSS简写,RN需要单独设置属性
  3. 布局系统: HTML支持Grid和Flexbox,RN主要使用Flexbox
  4. 平台差异: RN需要考虑iOS和Android的平台差异
  5. 性能优化: 两者都有各自的性能优化策略

理解这些差异有助于在跨平台开发中做出正确的技术选择,并编写更高效的代码。