@cniot/rn-swiper-code
v0.1.9
Published
@cniot/rn-swiper-code
Readme
React Native TripSwiper
一个用于展示和滑动切换行程信息的React Native组件,支持自定义内容、滑动切换和点击导航。
特性
- 🎨 支持多个行程卡片的滑动切换
- 📏 支持左右滑动和点击小圆点切换行程
- 🔄 流畅的动画过渡效果
- 🌐 完全可定制的UI样式
- ⏳ 支持自定义渲染内容
- 🎯 完全类型化的 TypeScript 支持
- 📱 适配不同屏幕尺寸
- 🔌 易于集成到现有项目中
安装
# 使用 npm
npm install @cniot/rn-swiper-code
# 使用 yarn
yarn add @cniot/rn-swiper-code在线预览
您可以使用以下react-live代码在线预览TripSwiper组件的效果,预览界面会模拟iPhone 15的外观,让您能够直观地看到组件在移动设备上的显示效果。
// 引入必要的依赖
import React from 'react';
import { View, Text, StyleSheet, Image } from 'react-native';
import { RNTripSwiper } from '@cniot/rn-swiper-code';
// iPhone 15 样式容器
const IPhoneFrame = ({ children }) => (
<div style={{
width: 375,
height: 812,
margin: '0 auto',
position: 'relative',
overflow: 'hidden',
borderRadius: 44,
backgroundColor: 'white',
boxShadow: '0 0 0 11px #1a1a1a, 0 0 0 13px #000, 0 0 34px rgba(0, 0, 0, 0.2)',
}}>
{/* 顶部刘海 */}
<div style={{
position: 'absolute',
top: 0,
left: '50%',
transform: 'translateX(-50%)',
width: 160,
height: 34,
backgroundColor: '#000',
borderBottomLeftRadius: 18,
borderBottomRightRadius: 18,
zIndex: 10,
}}></div>
{/* 状态栏 */}
<div style={{
height: 44,
width: '100%',
backgroundColor: '#f8f8f8',
display: 'flex',
justifyContent: 'space-between',
alignItems: 'center',
padding: '0 20px',
boxSizing: 'border-box',
fontSize: 12,
color: '#000',
fontWeight: 'bold',
zIndex: 5,
}}>
<span>9:41</span>
<div style={{ display: 'flex', gap: 5 }}>
<span>📶</span>
<span>📡</span>
<span>🔋</span>
</div>
</div>
{/* 内容区域 */}
<div style={{
height: 'calc(100% - 44px)',
width: '100%',
overflow: 'hidden',
backgroundColor: '#f8f8f8',
}}>
{children}
</div>
</div>
);
// 示例组件
const Example = () => {
const tripData = [
{
title: '行程信息',
items: [
{ label: '行程编号', value: 'TC-001' },
{ label: '计划出发时间', value: '8:00:00' },
{ label: '路线代码', value: 'TC-Route' },
],
},
{
title: '行程信息',
items: [
{ label: '行程编号', value: 'TC-002' },
{ label: '计划出发时间', value: '10:30:00' },
{ label: '路线代码', value: 'TC-Route' },
],
},
];
return (
<IPhoneFrame>
<View style={{ flex: 1, padding: 16 }}>
<RNTripSwiper tripData={tripData} />
</View>
</IPhoneFrame>
);
};
// 渲染示例
render(<Example />);提示:在实际的react-live环境中,您可以左右滑动或点击底部的小圆点来切换不同的行程卡片。
必要依赖
本组件库依赖以下基础包,这些包通常在 React Native 项目中已经存在:
- react (>=16.8.0)
- react-native (>=0.60.0)
- expo-status-bar (如果使用Expo)
注意:本组件使用了React Hooks,因此要求React版本不低于16.8.0。
使用指南
基本用法
import React from 'react';
import { View } from 'react-native';
import { RNTripSwiper } from '@cniot/rn-swiper-code';
const MyComponent = () => {
return (
<View style={{ padding: 16 }}>
<RNTripSwiper
tripData={[
{
title: '行程信息',
items: [
{ label: '行程编号', value: 'TC-001' },
{ label: '计划出发时间', value: '8:00:00' },
{ label: '路线代码', value: 'TC-Route' },
],
},
{
title: '行程信息',
items: [
{ label: '行程编号', value: 'TC-002' },
{ label: '计划出发时间', value: '10:30:00' },
{ label: '路线代码', value: 'TC-Route' },
],
}
]}
/>
</View>
);
};
export default MyComponent;自定义渲染单个内容项
以下示例展示了如何自定义渲染单个内容项,并在iPhone 15模拟器中预览效果:
// 引入必要的依赖
import React from 'react';
import { View, Text, StyleSheet } from 'react-native';
import { RNTripSwiper } from '@cniot/rn-swiper-code';
// iPhone 15 样式容器
const IPhoneFrame = ({ children }) => (
<div style={{
width: 375,
height: 812,
margin: '0 auto',
position: 'relative',
overflow: 'hidden',
borderRadius: 44,
backgroundColor: 'white',
boxShadow: '0 0 0 11px #1a1a1a, 0 0 0 13px #000, 0 0 34px rgba(0, 0, 0, 0.2)',
}}>
{/* 顶部刘海 */}
<div style={{
position: 'absolute',
top: 0,
left: '50%',
transform: 'translateX(-50%)',
width: 160,
height: 34,
backgroundColor: '#000',
borderBottomLeftRadius: 18,
borderBottomRightRadius: 18,
zIndex: 10,
}}></div>
{/* 状态栏 */}
<div style={{
height: 44,
width: '100%',
backgroundColor: '#f8f8f8',
display: 'flex',
justifyContent: 'space-between',
alignItems: 'center',
padding: '0 20px',
boxSizing: 'border-box',
fontSize: 12,
color: '#000',
fontWeight: 'bold',
zIndex: 5,
}}>
<span>9:41</span>
<div style={{ display: 'flex', gap: 5 }}>
<span>📶</span>
<span>📡</span>
<span>🔋</span>
</div>
</div>
{/* 内容区域 */}
<div style={{
height: 'calc(100% - 44px)',
width: '100%',
overflow: 'hidden',
backgroundColor: '#f8f8f8',
}}>
{children}
</div>
</div>
);
// 示例组件
const CustomItemExample = () => {
// 自定义样式
const styles = {
customItem: {
flexDirection: 'row',
justifyContent: 'space-between',
alignItems: 'center',
width: '100%',
},
customLabel: {
fontSize: 14,
color: '#1A2138',
fontWeight: '500',
},
customValueContainer: {
flexDirection: 'row',
alignItems: 'center',
},
customValue: {
fontSize: 14,
color: '#1A2138',
fontWeight: 'bold',
marginRight: 8,
},
badge: {
backgroundColor: '#FF6B6B',
paddingHorizontal: 6,
paddingVertical: 2,
borderRadius: 4,
},
badgeText: {
color: 'white',
fontSize: 10,
fontWeight: 'bold',
},
};
const tripData = [
{
title: '行程信息',
items: [
{
label: '行程编号',
value: 'TC-001',
render: () => (
<View style={styles.customItem}>
<Text style={styles.customLabel}>行程编号</Text>
<View style={styles.customValueContainer}>
<Text style={styles.customValue}>TC-001</Text>
<View style={styles.badge}>
<Text style={styles.badgeText}>VIP</Text>
</View>
</View>
</View>
),
},
{ label: '计划出发时间', value: '8:00:00' },
{ label: '路线代码', value: 'TC-Route' },
],
},
{
title: '行程信息',
items: [
{
label: '行程编号',
value: 'TC-002',
render: () => (
<View style={styles.customItem}>
<Text style={styles.customLabel}>行程编号</Text>
<View style={styles.customValueContainer}>
<Text style={styles.customValue}>TC-002</Text>
<View style={styles.badge}>
<Text style={styles.badgeText}>普通</Text>
</View>
</View>
</View>
),
},
{ label: '计划出发时间', value: '10:30:00' },
{ label: '路线代码', value: 'TC-Route' },
],
},
];
return (
<IPhoneFrame>
<View style={{ flex: 1, padding: 16 }}>
<RNTripSwiper tripData={tripData} />
</View>
</IPhoneFrame>
);
};
// 渲染示例
render(<CustomItemExample />);以下是常规代码示例,您可以复制到您的项目中:
import React from 'react';
import { View, Text, StyleSheet } from 'react-native';
import { RNTripSwiper } from '@cniot/rn-swiper-code';
const MyComponent = () => {
const tripData = [
{
title: '行程信息',
items: [
{
label: '行程编号',
value: 'TC-001',
render: () => (
<View style={styles.customItem}>
<Text style={styles.customLabel}>行程编号</Text>
<View style={styles.customValueContainer}>
<Text style={styles.customValue}>TC-001</Text>
<View style={styles.badge}>
<Text style={styles.badgeText}>VIP</Text>
</View>
</View>
</View>
),
},
{ label: '计划出发时间', value: '8:00:00' },
{ label: '路线代码', value: 'TC-Route' },
],
},
// 更多行程...
];
return (
<View style={{ flex: 1 }}>
<RNTripSwiper tripData={tripData} />
</View>
);
};
const styles = StyleSheet.create({
customItem: {
flexDirection: 'row',
justifyContent: 'space-between',
alignItems: 'center',
width: '100%',
},
customLabel: {
fontSize: 14,
color: '#1A2138',
fontWeight: '500',
},
customValueContainer: {
flexDirection: 'row',
alignItems: 'center',
},
customValue: {
fontSize: 14,
color: '#1A2138',
fontWeight: 'bold',
marginRight: 8,
},
badge: {
backgroundColor: '#FF6B6B',
paddingHorizontal: 6,
paddingVertical: 2,
borderRadius: 4,
},
badgeText: {
color: 'white',
fontSize: 10,
fontWeight: 'bold',
},
});
export default MyComponent;自定义整个内容区域
以下示例展示了如何自定义整个内容区域,并在iPhone 15模拟器中预览效果:
// 引入必要的依赖
import React from 'react';
import { View, Text, StyleSheet, Image } from 'react-native';
import { RNTripSwiper } from '@cniot/rn-swiper-code';
// iPhone 15 样式容器
const IPhoneFrame = ({ children }) => (
<div style={{
width: 375,
height: 812,
margin: '0 auto',
position: 'relative',
overflow: 'hidden',
borderRadius: 44,
backgroundColor: 'white',
boxShadow: '0 0 0 11px #1a1a1a, 0 0 0 13px #000, 0 0 34px rgba(0, 0, 0, 0.2)',
}}>
{/* 顶部刘海 */}
<div style={{
position: 'absolute',
top: 0,
left: '50%',
transform: 'translateX(-50%)',
width: 160,
height: 34,
backgroundColor: '#000',
borderBottomLeftRadius: 18,
borderBottomRightRadius: 18,
zIndex: 10,
}}></div>
{/* 状态栏 */}
<div style={{
height: 44,
width: '100%',
backgroundColor: '#f8f8f8',
display: 'flex',
justifyContent: 'space-between',
alignItems: 'center',
padding: '0 20px',
boxSizing: 'border-box',
fontSize: 12,
color: '#000',
fontWeight: 'bold',
zIndex: 5,
}}>
<span>9:41</span>
<div style={{ display: 'flex', gap: 5 }}>
<span>📶</span>
<span>📡</span>
<span>🔋</span>
</div>
</div>
{/* 内容区域 */}
<div style={{
height: 'calc(100% - 44px)',
width: '100%',
overflow: 'hidden',
backgroundColor: '#f8f8f8',
}}>
{children}
</div>
</div>
);
// 示例组件
const CustomContentExample = () => {
// 自定义样式
const styles = {
customContent: {
backgroundColor: '#F5F7FA',
borderRadius: 8,
padding: 12,
},
customRow: {
flexDirection: 'row',
justifyContent: 'space-between',
alignItems: 'center',
paddingVertical: 10,
},
customRowLabel: {
fontSize: 14,
color: '#1A2138',
fontWeight: '500',
},
customRowValue: {
fontSize: 14,
color: '#1A2138',
fontWeight: 'bold',
},
divider: {
height: 1,
backgroundColor: '#E2E8F0',
width: '100%',
},
transportContainer: {
flexDirection: 'row',
alignItems: 'center',
},
transportIcon: {
width: 20,
height: 20,
marginRight: 8,
},
};
const tripData = [
{
title: '行程信息',
items: [
{ label: '行程编号', value: 'TC-001' },
{ label: '计划出发时间', value: '8:00:00' },
],
},
{
title: '行程信息',
renderContent: () => (
<View style={styles.customContent}>
<View style={styles.customRow}>
<Text style={styles.customRowLabel}>目的地</Text>
<Text style={styles.customRowValue}>上海</Text>
</View>
<View style={styles.divider} />
<View style={styles.customRow}>
<Text style={styles.customRowLabel}>出发时间</Text>
<Text style={styles.customRowValue}>9:30:00</Text>
</View>
<View style={styles.divider} />
<View style={styles.customRow}>
<Text style={styles.customRowLabel}>交通方式</Text>
<View style={styles.transportContainer}>
<Image
source={{ uri: 'https://via.placeholder.com/20' }}
style={styles.transportIcon}
/>
<Text style={styles.customRowValue}>高铁</Text>
</View>
</View>
</View>
),
},
];
return (
<IPhoneFrame>
<View style={{ flex: 1, padding: 16 }}>
<RNTripSwiper tripData={tripData} />
</View>
</IPhoneFrame>
);
};
// 渲染示例
render(<CustomContentExample />);以下是常规代码示例,您可以复制到您的项目中:
import React from 'react';
import { View, Text, StyleSheet, Image } from 'react-native';
import { RNTripSwiper } from '@cniot/rn-swiper-code';
const MyComponent = () => {
const tripData = [
{
title: '行程信息',
items: [
{ label: '行程编号', value: 'TC-001' },
{ label: '计划出发时间', value: '8:00:00' },
],
},
{
title: '行程信息',
renderContent: () => (
<View style={styles.customContent}>
<View style={styles.customRow}>
<Text style={styles.customRowLabel}>目的地</Text>
<Text style={styles.customRowValue}>上海</Text>
</View>
<View style={styles.divider} />
<View style={styles.customRow}>
<Text style={styles.customRowLabel}>出发时间</Text>
<Text style={styles.customRowValue}>9:30:00</Text>
</View>
<View style={styles.divider} />
<View style={styles.customRow}>
<Text style={styles.customRowLabel}>交通方式</Text>
<View style={styles.transportContainer}>
<Image
source={{ uri: 'https://via.placeholder.com/20' }}
style={styles.transportIcon}
/>
<Text style={styles.customRowValue}>高铁</Text>
</View>
</View>
</View>
),
},
// 更多行程...
];
return (
<View style={{ flex: 1 }}>
<RNTripSwiper tripData={tripData} />
</View>
);
};
const styles = StyleSheet.create({
customContent: {
backgroundColor: '#F5F7FA',
borderRadius: 8,
padding: 12,
},
customRow: {
flexDirection: 'row',
justifyContent: 'space-between',
alignItems: 'center',
paddingVertical: 10,
},
customRowLabel: {
fontSize: 14,
color: '#1A2138',
fontWeight: '500',
},
customRowValue: {
fontSize: 14,
color: '#1A2138',
fontWeight: 'bold',
},
divider: {
height: 1,
backgroundColor: '#E2E8F0',
width: '100%',
},
transportContainer: {
flexDirection: 'row',
alignItems: 'center',
},
transportIcon: {
width: 20,
height: 20,
marginRight: 8,
},
});
export default MyComponent;API 参考
RNTripSwiper Props
| 属性 | 类型 | 默认值 | 描述 | |------|------|--------|------| | tripData | Array | 默认示例数据 | 行程数据数组 | | style | StyleProp | - | 应用于容器的自定义样式 |
TripData 类型
interface TripData {
title: string; // 行程卡片标题
items?: TripItem[]; // 行程内容项数组
renderContent?: () => React.ReactNode; // 自定义渲染整个内容区域的函数
}
interface TripItem {
label: string; // 内容项的标签
value: string; // 内容项的值
render?: () => React.ReactNode; // 自定义渲染单个内容项的函数
}注意事项
- 组件内部使用了
PanResponder来处理滑动手势,支持左右滑动切换行程 - 滑动切换有阈值限制,需要足够的滑动距离才会触发切换
- 在滑动动画进行中,组件会暂时禁用新的滑动操作,以避免动画冲突
- 组件设计为只有内容区域轮播,标题和页码保持固定,但页码会随着翻页变化
- 当提供
items属性时,将忽略tripCode、planedStartTime和routeCode属性 - 组件内部的样式可以通过
style属性进行覆盖 - 在Android设备上,可能需要额外的配置来确保阴影效果正常显示
- 当使用自定义渲染函数时,需要自行处理样式和布局
- 组件默认不处理网络请求,如需动态加载数据,需要在父组件中实现
- 在低端设备上,大量的动画效果可能会影响性能,建议适当减少动画效果
- 组件使用了React Hooks,确保您的React版本支持Hooks功能
性能优化建议
- 避免在渲染函数中创建新的函数或对象,应使用useCallback和useMemo
- 对于大量数据的场景,考虑使用分页加载
- 使用PureComponent或React.memo来避免不必要的重新渲染
- 图片资源应进行适当的压缩和缓存处理
- 避免在滑动动画过程中执行复杂的计算或渲染操作
许可证
MIT
