首页 > 作文

你知道怎么基于 React 封装一个组件吗

更新时间:2023-04-04 18:46:45 阅读: 评论:0

目录
antd 是如何封装组件的仓库地址divider 组件源代码如何暴露组件属性如何设置统一类名前缀如何处理样式与类名divider 组件样式源代码总结

前言

很多小伙伴在第一次尝试封装组件时会和我一样碰到许多问题,比如人家的组件会有 color 属性,我们在使用组件时传入组件文档中说明的属性值如 primary ,那么这个组件的字体颜色会变为 primary 对应的颜色,这是如何做到的?还有别人封装的组件类名都有自己独特的前缀,这是如何处理的呢,难道是 css 类名全部加上前缀吗,这也太麻烦了!

如果你正在困惑这些问题,你可以看看这篇文章。

我会参照antd的divider组件来讲述如何基于react封装一个组件,以及解答上述的一些问题,请耐心看完!

antd 是如何封装组件的

仓库地址

divider 组件在下图对应目录下 (代码我会拷贝过来,感兴趣的还是可以去克隆一下仓库)

divider 组件源代码

antd 的源码使用了 typescript 语法,因此不了解语法的同学要及时了解哦!

import * as react from 'react';import classnames from 'classnames';import { configconsumer, configconsumerprops } from '../config-provider';export interface dividerprops {    prefixcls?: string;    type?: 'horizontal' | 'vertical';    orientation?: 'left' | 'right' | 'center';    classname?: string;    children?: react.reactnode;    dashed?: boolean;    style?: react.cssproperties;    plain?: boolean;}const divider: react.fc<dividerprops> = props => (    <configconsumer>        {({ getprefixcls, direction }: configconsumerprops) => {            const {                prefixcls: customizeprefixcls,                type = 'horizontal',                orientation = 'center',                classname,                children,                dashed,                plain,                ...restprops            } = props;            const prefixcls = getprefixcls('divider', customizeprefixcls);            const orientationprefix = orientation.length > 0 ? `-${orientation}` : orientation;            const haschildren = !!children;            const classstring = classnames(                prefixcls,                `${prefixcls}-${type}`,                {                    [`${prefixcls}-with-text`]: haschildren,                    [`${prefixcls}-with-text${orientationprefix}`]: haschildren,                    [`${prefixcls}-dashed`]: !!dashed,                    [`${prefixcls}-plain`]: !!plain,                    [`${prefixcls}-rtl`]: direction === 'rtl',                },                classname,      车同轨      );            return (                <div classname={classstring} {...restprops} role="parator">                    {children && <span classname={`${prefixcls}-inner-texeverytime 太阳的后裔t`}>{children}</span>}                </div>            );        }}    </configconsumer>);export default divider;

如何暴露组件属性

在源码中,最先看到的是以下内容,这些属性也就是divider组件所暴露的属性,我们可以<divider type='vertical' />这样来传入 type 属性,那么 divider 分割线样式就会渲染为垂直分割线,是不是很熟悉!

export interface dividerprops { // interface 是 typescript 的语法    prefixcls?: string;    type?: 'horizontal' | 'vertical'; // 限定 type 只能传入两个值中的一个    orientation?: 'left' | 'right' | 'center';    classname?: string;    children?: react.reactnode;    dashed?: boolean;    style?: react.cssproperties;    plain?: boolean;}

在上面的属性中,我们还发现 classname 和 style是比较常见的属性,这代表我们可以<divider type='vertical' classname='myclassname' style={{width: '1em'}} />这样使用这些属性。

如何设置统一类名前缀

我们知道,antd 的组件类名会有他们独特的前缀ant-,这是如何处理的呢?继续看源码韩国大学。

<configconsumer>    {({ getprefixcls, direction }: configconsumerprops) => {        const {            prefixcls: customizeprefixcls,            type = 'horizontal',            orientation = 'center',            classname,            children,            dashed,            plain,            ...restprops        } = props;        const prefixcls = getprefixcls('divider', customizeprefixcls);

从源码中,我们发现 prefixcls ,这里是通过 getprefixcls 方法生成,再看看 getprefixcls 方法的源码,如下。

export interface configconsumerprops {  ...  getprefixcls: (suffixcls?: string, customizeprefixcls?: string) => string;  ...}const defaultgetprefixcls = (suffixcls?: string, customizeprefixcls?: string) => {  if (customizeprefixcls) return customizeprefixcls;  return suffixcls ? `ant-${suffixcls}` : 'ant';};

不难发现此时会生成的类名前缀为ant-divider

如何处理样式与类名

我们封装的组件肯定是有预设的样式,又因为样式要通过类名来定义,而我们传入的属性值则会决定组件上要添加哪个类名,这又是如何实现的呢?下面看源码。

import classnames from 'classnames';const classstring = classnames(    prefixcls,    `${prefixcls}-${type}`,    {        [`${prefixcls}-with-text`]: haschildren,        [`${prefixcls}-with-text${orientationprefix}`]: haschildren,        [`${prefixcls}-dashed`]: !!dashed,        [`${prefixcls}-plain`]: !!plain,        [`${prefixcls}-rtl`]: direction === 'rtl',    },    classname,);return (    <div classname={classstring} {...restprops} role="parator">        {children && <span classname={`${prefixcls}-inner-text`}>{children}</span>}    </div>);

我们发现,它通过 classnames 方法)定义了一个所有类名的常量,然后传给了 div 中的 classname 属性。

其实生成的类名也就是ant-divider-horizontal这个样子,那么css中以此类名定义的样式也就自然会生效了。而 classname 和 style 属性则是通过{...restprops}来传入。

最后我们再看看它的css样式代码是怎么写的!

divider 组件样式源代码老朋友好久不见

antd 组件的样式使用 less 书写,不了解 less 语法的同学一定要了解一下。

@import '../../style/themes/index';@import '../../style/mixins/index';@divider-prefix-cls: ~'@{ant-prefix}-divider'; // 可以看到这里对应的也就是之前说到的类名前缀.@{divider-prefix-cls} {  .ret-component();  border-top: @border-width-ba solid @divider-color;  &-vertical { // 这里的完整类名其实就是 ant-divider-vertical, 也就是 divider 组件的 type 属性值为 v元宵节活动方案ertical 时对应的样式    position: relative;    top: -0.06em;    display: inline-block;    height: 0.9em;    margin: 0 8px;    vertical-align: middle;    border-top: 0;    border-left: @border-width-ba solid @divider-color;  }  &-horizontal {    display: flex;    clear: both;    width: 100%;    min-width: 100%;     margin: 24px 0;  }  &-horizontal&-with-text {    display: flex;    margin: 16px 0;    color: @heading-color;    font-weight: 500;    font-size: @font-size-lg;    white-space: nowrap;    text-align: center;    border-top: 0;    border-top-color: @divider-color;    &::before,    &::after {      position: relative;      top: 50%;      width: 50%;      border-top: @border-width-ba solid transparent;      // chrome not accept `inherit` in `border-top`      border-top-color: inherit;      border-bottom: 0;      transform: translatey(50%);      content: '';    }  }  &-horizontal&-with-text-left {    &::before {      top: 50%;      width: @divider-orientation-margin;    }    &::after {      top: 50%;      width: 100% - @divider-orientation-margin;    }  }  &-horizontal&-with-text-right {    &::before {      top: 50%;      width: 100% - @divider-orientation-margin;    }    &::after {      top: 50%;      width: @divider-orientation-margin;    }  }  &-inner-text {    display: inline-block;    padding: 0 @divider-text-padding;  }  &-dashed {    background: none;    border-color: @divider-color;    border-style: dashed;    border-width: @border-width-ba 0 0;  }  &-horizontal&-with-text&-dashed {    border-top: 0;    &::before,    &::after {      border-style: dashed none none;    }  }  &-vertical&-dashed {    border-width: 0 0 0 @border-width-ba;  }  &-plain&-with-text {    color: @text-color;    font-weight: normal;    font-size: @font-size-ba;  }}@import './rtl';

这样一来,我相信同学们也大概了解如何去封装一个组件以及关键点了,在源码中还有很多地方值得我们学习,比如这里的 configconsumer 的定义与使用,感兴趣的同学欢迎一起交流。

总结

本篇文章就到这里了,希望能够给你带来帮助,也希望您能够多多关注www.887551.com的更多内容!

本文发布于:2023-04-04 18:46:43,感谢您对本站的认可!

本文链接:https://www.wtabcd.cn/fanwen/zuowen/3fd1c1f3c5b40761593b8f66077a02b4.html

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。

本文word下载地址:你知道怎么基于 React 封装一个组件吗.doc

本文 PDF 下载地址:你知道怎么基于 React 封装一个组件吗.pdf

标签:组件   属性   样式   前缀
相关文章
留言与评论(共有 0 条评论)
   
验证码:
Copyright ©2019-2022 Comsenz Inc.Powered by © 专利检索| 网站地图