RN组件库 - Button 组件

从零构建 React Native 组件库,作为一个前端er~谁不想拥有一个自己的组件库呢

1、定义 Button 基本类型 type.ts

import type {StyleProp, TextStyle, ViewProps} from 'react-native';
import type {TouchableOpacityProps} from '../TouchableOpacity/type';
import type Loading from '../Loading';// 五种按钮类型
export type ButtonType =| 'primary'| 'success'| 'warning'| 'danger'| 'default';
// 四种按钮大小
export type ButtonSize = 'large' | 'small' | 'mini' | 'normal';
// 加载中组件类型
type LoadingProps = React.ComponentProps<typeof Loading>;
// 按钮的基本属性
// extends Pick的作用是:
// 继承父类型的属性和方法:通过extends关键字,子类型可以继承父类型的所有属性和方法。
// 选取父类型的特定属性:通过Pick工具类型,从父类型中选取需要的属性,并将其添加到子类型中。
export interface ButtonPropsextends Pick<ViewProps, 'style' | 'testID'>,Pick<TouchableOpacityProps,'onPress' | 'onLongPress' | 'onPressIn' | 'onPressOut'> {/*** 类型,可选值为 primary success warning danger* @default default*/type?: ButtonType;/*** 尺寸,可选值为 large small mini* @default normal*/size?: ButtonSize;/*** 按钮颜色,支持传入 linear-gradient 渐变色*/color?: string;/*** 左侧图标名称或自定义图标组件*/icon?: React.ReactNode;/*** 图标展示位置,可选值为 right* @default left*/iconPosition?: 'left' | 'right';/*** 是否为朴素按钮*/plain?: boolean;/*** 是否为方形按钮*/square?: boolean;/*** 是否为圆形按钮*/round?: boolean;/*** 是否禁用按钮*/disabled?: boolean;/*** 是否显示为加载状态*/loading?: boolean;/*** 加载状态提示文字*/loadingText?: string;/*** 加载图标类型*/loadingType?: LoadingProps['type'];/*** 加载图标大小*/loadingSize?: number;textStyle?: StyleProp<TextStyle>;children?: React.ReactNode;
}

2、动态生成样式对象style.ts

import {StyleSheet} from 'react-native';
import type {ViewStyle, TextStyle} from 'react-native';
import type {ButtonType, ButtonSize} from './type';type Params = {type: ButtonType;size: ButtonSize;plain?: boolean;
};type Styles = {button: ViewStyle;disabled: ViewStyle;plain: ViewStyle;round: ViewStyle;square: ViewStyle;text: TextStyle;
};const createStyle = (theme: DiceUI.Theme,{type, size, plain}: Params,
): Styles => {// Record 是一种高级类型操作,用于创建一个对象类型// 其中键的类型由第一个参数指定(ButtonType),值的类型由第二个参数指定(ViewStyle)const buttonTypeStyleMaps: Record<ButtonType, ViewStyle> = {default: {backgroundColor: theme.button_default_background_color,borderColor: theme.button_default_border_color,borderStyle: 'solid',borderWidth: theme.button_border_width,},danger: {backgroundColor: theme.button_danger_background_color,borderColor: theme.button_danger_border_color,borderStyle: 'solid',borderWidth: theme.button_border_width,},primary: {backgroundColor: theme.button_primary_background_color,borderColor: theme.button_primary_border_color,borderStyle: 'solid',borderWidth: theme.button_border_width,},success: {backgroundColor: theme.button_success_background_color,borderColor: theme.button_success_border_color,borderStyle: 'solid',borderWidth: theme.button_border_width,},warning: {backgroundColor: theme.button_warning_background_color,borderColor: theme.button_warning_border_color,borderStyle: 'solid',borderWidth: theme.button_border_width,},};const buttonSizeStyleMaps: Record<ButtonSize, ViewStyle> = {normal: {},small: {height: theme.button_small_height,},large: {height: theme.button_large_height,width: '100%',},mini: {height: theme.button_mini_height,},};const contentPadding: Record<ButtonSize, ViewStyle> = {normal: {paddingHorizontal: theme.button_normal_padding_horizontal,},small: {paddingHorizontal: theme.button_small_padding_horizontal,},large: {},mini: {paddingHorizontal: theme.button_mini_padding_horizontal,},};const textSizeStyleMaps: Record<ButtonSize, TextStyle> = {normal: {fontSize: theme.button_normal_font_size,},large: {fontSize: theme.button_default_font_size,},mini: {fontSize: theme.button_mini_font_size,},small: {fontSize: theme.button_small_font_size,},};const textTypeStyleMaps: Record<ButtonType, TextStyle> = {default: {color: theme.button_default_color,},danger: {color: plain? theme.button_danger_background_color: theme.button_danger_color,},primary: {color: plain? theme.button_primary_background_color: theme.button_primary_color,},success: {color: plain? theme.button_success_background_color: theme.button_success_color,},warning: {color: plain? theme.button_warning_background_color: theme.button_warning_color,},};return StyleSheet.create<Styles>({button: {alignItems: 'center',borderRadius: theme.button_border_radius,flexDirection: 'row',height: theme.button_default_height,justifyContent: 'center',overflow: 'hidden',position: 'relative',...buttonTypeStyleMaps[type],...buttonSizeStyleMaps[size],...contentPadding[size],},disabled: {opacity: theme.button_disabled_opacity,},plain: {backgroundColor: theme.button_plain_background_color,},round: {borderRadius: theme.button_round_border_radius,},square: {borderRadius: 0,},text: {...textTypeStyleMaps[type],...textSizeStyleMaps[size],},});
};export default createStyle;

3、实现 Button 组件

import React, {FC, memo} from 'react';
import {View, ViewStyle, StyleSheet, Text, TextStyle} from 'react-native';
import TouchableOpacity from '../TouchableOpacity';
import {useThemeFactory} from '../Theme';
import Loading from '../Loading';
import createStyle from './style';
import type {ButtonProps} from './type';const Button: FC<ButtonProps> = memo(props => {const {type = 'default',size = 'normal',loading,loadingText,loadingType,loadingSize,icon,iconPosition = 'left',color,plain,square,round,disabled,textStyle,children,// 对象的解构操作,在末尾使用...会将剩余的属性都收集到 rest 对象中。...rest} = props;// useThemeFactory 调用 createStyle 函数根据入参动态生成一个 StyleSheet.create<Styles> 对象const {styles} = useThemeFactory(createStyle, {type, size, plain});const text = loading ? loadingText : children;// 将属性合并到一个新的样式对象中,并返回这个新的样式对象。const textFlattenStyle = StyleSheet.flatten<TextStyle>([styles.text,!!color && {color: plain ? color : 'white'},textStyle,]);// 渲染图标const renderIcon = () => {const defaultIconSize = textFlattenStyle.fontSize;const iconColor = color ?? (textFlattenStyle.color as string);let marginStyles: ViewStyle;if (!text) {marginStyles = {};} else if (iconPosition === 'left') {marginStyles = {marginRight: 4};} else {marginStyles = {marginLeft: 4};}return (<>{icon && loading !== true && (<View style={marginStyles}>{/* React 提供的一个顶层 API,用于检查某个值是否为 React 元素 */}{React.isValidElement(icon)? React.cloneElement(icon as React.ReactElement<any, string>, {size: defaultIconSize,color: iconColor,}): icon}</View>)}{loading && (<Loading// ?? 可选链操作符,如果 loadingSize 为 null 或 undefined ,就使用 defaultIconSize 作为默认值size={loadingSize ?? defaultIconSize}type={loadingType}color={iconColor}style={marginStyles}/>)}</>);};// 渲染文本const renderText = () => {if (!text) {return null;}return (<Text selectable={false} numberOfLines={1} style={textFlattenStyle}>{text}</Text>);};return (<TouchableOpacity{...rest}disabled={disabled}activeOpacity={0.6}style={[styles.button,props.style,plain && styles.plain,round && styles.round,square && styles.square,disabled && styles.disabled,// !!是一种类型转换的方法,它可以将一个值转换为布尔类型的true或false!!color && {borderColor: color},!!color && !plain && {backgroundColor: color},]}>{iconPosition === 'left' && renderIcon()}{renderText()}{iconPosition === 'right' && renderIcon()}</TouchableOpacity>);
});export default Button;

4、对外导出 Botton 组件及其类型文件

import Button from './Button';export default Button;
export {Button};
export type {ButtonProps, ButtonSize, ButtonType} from './type';

5、主题样式

动态生成样式对象调用函数

import {useMemo} from 'react';
import {createTheming} from '@callstack/react-theme-provider';
import type {StyleSheet} from 'react-native';
import {defaultTheme} from '../styles';
// 创建主题对象:调用 createTheming 函数并传入一个默认主题作为参数
export const {ThemeProvider, withTheme, useTheme} = createTheming<DiceUI.Theme>(defaultTheme as DiceUI.Theme,
);type ThemeFactoryCallBack<T extends StyleSheet.NamedStyles<T>> = {styles: T;theme: DiceUI.Theme;
};export function useThemeFactory<T extends StyleSheet.NamedStyles<T>, P>(fun: (theme: DiceUI.Theme, ...extra: P[]) => T,...params: P[]
): ThemeFactoryCallBack<T> {// 钩子,用于在函数组件中获取当前的主题const theme = useTheme();const styles = useMemo(() => fun(theme, ...params), [fun, theme, params]);return {styles, theme};
}export default {ThemeProvider,withTheme,useTheme,useThemeFactory,
};

6、Demo 演示

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/web/32302.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

webpack安装sass

package.json文件 {"devDependencies": {"sass-loader": "^7.2.0","sass": "^1.22.10","fibers": "^4.0.1"} }这个不用webpack.config.js module.exports {module: {rules: [{test: /\.s[ac]ss$/i,u…

FlinkSQL开发经验分享

最近做了几个实时数据开发需求&#xff0c;也不可避免地在使用Flink的过程中遇到了一些问题&#xff0c;比如数据倾斜导致的反压、interval join、开窗导致的水位线失效等问题&#xff0c;通过思考并解决这些问题&#xff0c;加深了我对Flink原理与机制的理解&#xff0c;因此将…

DC-DC 高压降压、非隔离AC-DC、提供强大的动力,选择优质电源芯片-(昱灿)

畅享长续航&#xff0c;尽在我们的充电芯片&#xff01; 无论是手机、平板还是智能设备&#xff0c;长时间使用后电量不足总是令人头疼。然而&#xff0c;我们的充电芯片将为您带来全新的充电体验&#xff01;采用先进的技术&#xff0c;我们的充电芯片能够提供快速而稳定的充电…

威纶通触摸屏软件出现显示异常问题(显示黑色)处理方法

异常现象 电脑端显示异常&#xff0c;显示黑色 解决方法 Step1&#xff1a;软件根目录查找DisplaySetting.exe Step2&#xff1a;勾选第1或第2项&#xff0c;重启软件即可 分享创作不易&#xff0c;请多多支持&#xff0c;点赞、收藏、关注&#xff01; Ending~

《计算机英语》 Unit 3 Software Engineering 软件工程

Section A Software Engineering Methodologies 软件工程方法论 Software development is an engineering process. 软件开发是一个工程过程。 The goal of researchers in software engineering is to find principles that guide the software development process and lea…

冲击2024年CSDN博客之星TOP1:CSDN文章质量分查询在哪里?

文章目录 一&#xff0c;2023年博客之星规则1&#xff0c;不高的入围门槛2&#xff0c;[CSDN博文质量分测评地址](https://www.csdn.net/qc) 二&#xff0c;高分秘籍1&#xff0c;要有目录2&#xff0c;文章长度要足够&#xff0c;我的经验是汉字加代码至少1000字。3&#xff0…

6G时代,即将来临!

日前&#xff0c;由未来移动通信论坛、紫金山实验室主办的2024全球6G技术大会在南京召开。本次大会以“创新预见6G未来”为主题&#xff0c;在大会开幕式上发布了协力推进全球6G统一标准行动的倡议和紫金山科技城加速培育以6G技术引领未来产业行动计划。 在我国已开展第五代移动…

会自动清除的文件——tempfile

原文链接&#xff1a;http://www.juzicode.com/python-tutorial-tempfile/ 在某些不需要持久保存文件的场景下&#xff0c;可以用tempfile模块生成临时文件或者文件夹&#xff0c;这些临时文件或者文件夹在使用完之后就会自动删除。 NamedTemporaryFile用来创建临时文件&…

6月27日云技术研讨会 | 中央集中架构新车型功能和网络测试解决方案

会议摘要 “软件定义汽车”新时代下&#xff0c;整车电气电气架构向中央-区域集中式发展已成为行业共识&#xff0c;车型架构的变革带来更复杂的整车功能定义、更多的新技术的应用&#xff08;如SOA服务化、TSN等&#xff09;和更短的车型研发周期&#xff0c;对整车和新产品研…

C语言| 数组的折半查找

数组的折半查找 折半查找&#xff1a;在已经排好序的一组数据中快速查找数据。 先排序&#xff0c;再使用折半查找。 【折半查找的运行过程】 1 存储数组下标 low最小的下标&#xff0c;mid中间的下标&#xff0c; high最大的下标 2 key存放查找的值&#xff0c;每一次对比后…

Acrobat Pro DC 2021:Mac/Win平台上全面高效的PDF编辑器

Acrobat Pro DC 2021是一款在Mac和Windows平台上广受欢迎的PDF编辑器&#xff0c;它凭借其全面的功能和高效的性能&#xff0c;为用户提供了卓越的PDF处理体验。 一、编辑功能全面强大 Acrobat Pro DC 2021允许用户轻松创建、编辑、合并、转换、签署和分享PDF文件。无论是对P…

一个电商创业者眼中的618:平台大变局

战役结束了&#xff0c;战斗还在继续。 一位朋友去年5月创业&#xff0c;网上卖咖啡&#xff0c;这个赛道很拥挤&#xff0c;时机也不好&#xff0c;今年是他参加第一个618。朋友说&#xff0c;今年的目标是锤炼团队&#xff0c;总结方法&#xff0c;以及最重要的——活下去。…

水系统阻力计算

所谓水泵的选取计算其实就是估算&#xff08;很多计算公式本身就是估算的&#xff09;&#xff0c;估算分的细致些考虑的内容全面些就是精确的计算。 特别补充&#xff1a;当设计流量在设备的额定流量附近时&#xff0c;上面所提到的阻力可以套用&#xff0c;更多的是往往都大…

【C++题解】1713 - 输出满足条件的整数3

问题&#xff1a;1713 - 输出满足条件的整数3 类型&#xff1a;简单循环 题目描述&#xff1a; 有一个数列&#xff0c;该数列的前 4 个数是&#xff1a; 1 4 7 10 &#xff1b; 请从键盘读入一个正整数 n &#xff0c;请通过观察前 4 项的规律&#xff0c;输出 1∼n 之间所有…

AudioSep:从音频中分离出特定声音(人声、笑声、噪音、乐器等)本地一键整合包下载

AudioSep是一种 AI 模型&#xff0c;可以使用自然语言查询进行声音分离。这一创新性的模型由Audio-AGI开发&#xff0c;使用户能够通过简单的语言描述来分离各种声音源。 比如在嘈杂的人流车流中说话的录音中&#xff0c;可以分别提取干净的人声说话声音和嘈杂的人流车流噪声。…

咖啡事故,上海Manner咖啡店,1天两起店员和顾客发生冲突

上海咖啡店Manner&#xff0c;一天的时间竟然发生两起店员和员工发生肢体冲突&#xff1a; 事情详情&#xff1a; Manner威海路716店事件: 店员泼顾客咖啡粉&#xff0c;随后被辞退品牌方回应媒体&#xff0c;表示将严肃处理Manner梅花路门店事件:顾客因等待时间长抱怨&…

解锁PDF处理新境界:轻松调整字体,让你的文档焕然一新!

数字化时代&#xff0c;PDF文件已经成为我们日常办公和学习中不可或缺的一部分。它们为我们提供了方便的阅读体验&#xff0c;同时也保证了文档内容的完整性和格式的统一性。然而&#xff0c;有时候我们可能会遇到一个问题&#xff1a;如何轻松调整PDF文件中的字体&#xff0c;…

Linux内核学习——linux内核体系结构(1)

1 Linux内核模式 学习的是Linux 0.11内核&#xff0c;采用的是单内核模式。单内核模式的主要优点是内核代码结构紧凑、执行速度快&#xff0c;但是层次结构性不强。 操作系统如何提供的服务流程&#xff1f; 应用主程序使用指定的参数值执行系统调用指令(int x80)&#xff0…

如何恢复 Mac 数据?适用于 Mac 的免费磁盘恢复软件

对于大多数 Mac 电脑用户来说&#xff0c;丢失数据是他们最不想遇到的噩梦之一。然而&#xff0c;无论我们多么小心地使用 Mac&#xff0c;多么有条理地存储重要文件&#xff0c;我们仍然有可能丢失 Mac 上的数据。某些硬件故障更有可能导致您意外丢失文件。除此之外&#xff0…

Linux htop命令使用

文章目录 简介界面介绍第一行第二行第三行第四行 如何使用 简介 htop 是一个类似于 top 的命令&#xff0c;但具有更丰富的功能和更友好的界面。它可以实时显示系统中各个进程的资源占用情况&#xff0c;如 CPU 使用率、内存使用率等。以下是对 htop 命令的完全解析&#xff1…