ReactベースのフロントエンドUIライブラリを構築する(4)-レイアウトコンポーネント

序文

        前の記事に続く#ReactベースのフロントエンドUIライブラリを構築する(3)-基本コンポーネントのアイコンとボタンコンポーネントを追加し続けますが、今回はレイアウトコンポーネントのBoxとCombineを記録します。

        この記事のコードは、主要なコア回路図コードを示しています。すべてのコードについては、リポジトリを参照してください:Giteeリポジトリ

        ページレイアウトに関しては、最も一般的なのはフレックスレイアウトであり、Boxコンポーネントはフレックスレイアウトのカプセル化です。さらに面倒なことはせずに、コードに取り掛かりましょう。src/componentフォルダの下に新しいフォルダBox作成し、その中に新しいファイルを作成しますindex.tsx

export interface BoxProps {
  children?: ReactNode;
  direction?: 'row' | 'row-reverse' | 'column' | 'column-reverse';
  wrap?: 'nowrap' | 'wrap' | 'wrap-reverse';
  alignItems?: 'center' | 'flex-start' | 'flex-end' | 'stretch';
  alignContent?: 'center' | 'flex-start' | 'flex-end' | 'space-between' | 'space-around';
  justifyContent?:
    | 'center'
    | 'flex-start'
    | 'flex-end'
    | 'space-between'
    | 'space-around'
    | 'stretch';
  padding?: number | string;
  width?: string;
  height?: string;
  flex?: string;
}

class Box extends PureComponent<BoxProps> {
  render() {
    const box = <BoxWrap {...this.props} />;

    return box;
  }
}

...

复制代码

        上記は、flexのCSSパラメーターに対応するいくつかの受信パラメーターを定義しています。コードに特定の各パラメーターを実装することで、コンポーネントを完成させることができます。次に、BoxWrapコンポーネントを実装します。

import styled from '@emotion/styled';
import { css } from '@emotion/core';

export const BoxWrap = styleWrap({
  className: prefixCls,
})(
  styled('div')((props: any) => {
      // 要实现的内容
  }),
);
复制代码

        シェルフは古い方法で設定されていますが、引き続きstyleWrapを使用してパブリックスタイルのレイヤーをラップし、内部でdivを使用して実行します。中央に実装されるコンテンツは、使用されるcssを返す必要があります。これがコアです。コンテンツ:

...
const {
    children,
    direction,
    wrap,
    justifyContent,
    alignItems,
    alignContent,
    span,
    flex,
    width,
    height,
    padding,
} = props;

...

return css`
    box-sizing: border-box;
    
    // direction
    ${direction != null &&
      css`
        flex-direction: ${direction};
      `}

    // wrap
    ${wrap != null &&
      css`
        flex-wrap: ${wrap};
      `}
      
    // justifyContent
    ${justifyContent != null &&
      css`
        justify-content: ${justifyContent};
      `}
      
    // ...
`
复制代码

        ご覧のとおり、これはcssを追加するだけで実現できます。これは非常に簡単です。子のプロパティは公に宣言されていませんがstyled、生成されたコンポーネントに渡された後に暗黙的にレンダリングされることを説明する必要があります。

        作成したら、コンポーネントの外部で次のように実装できます。

<Box direction="column" justifyContent="center">
    <div>1</div>
    <div>2</div>
    <div>3</div>
</Box>
复制代码

混ぜる

        Combineコンポーネントは、さまざまなコンポーネントを結合するために使用されます。Boxと同様に、スタイルベースのコンポーネントです。レイアウトの便宜のためにCSSをカプセル化したものです。フレックスは使用せず、インラインブロック要素の束を大きなdivでラップするだけです。src/components下に新しいCombineフォルダを作成し、フォルダの下に新しいファイルを作成しますindex.tsx

const Combine = ({
  children,
  sharedProps = {},
  spacing = 'smart',
  separator,
  ...rest
}: CombineProps) => {
  const { size = 'md' } = sharedProps;
  let isFirstItem: boolean;
  return (
    <CombineWrap spacing={spacing} {...rest}>
        {React.Children.map(children, (child) => (
            // 遍历child
            <>
                // 放置分隔符
                {separator && !isFirstItem ? <span className={separatorCls} key="separator">
                    {separator}
                  </span> : null
                }
                // 放置子元素
                <div className={itemCls}>
                    {React.cloneElement(child)}
                    ...
                </div>
            </>
        )}
    </CombineWrap>
  )
}
复制代码

上記のコードは、子要素とセパレーターのクラスを定義しています。

export const itemCls = prefixCls + '-item';
export const separatorCls = prefixCls + '-separator';
复制代码

        コンポーネントは、関連するコンポーネント間の距離を制御するための間隔パラメータを受け取ります。また、セパレータをカスタムセパレータとして設定することもできます。CombineWrapコンポーネントの実装を見てみましょう。

import styled from '@emotion/styled';
import { css } from '@emotion/core';

export const CombineWrap = styledWrap<{ spacing: string }>({
  // 接受自定义class
  className: prefixCls,
})(
  // 生成一个自定义样式包裹的div
  styled('div')((props) => {
    const {
      spacing,
      theme: { designTokens: DT },
    } = props;
    
    // spacingMap为designTokens里定义的常量
    const space = (DT as any)[spacingMap[spacing]];

    return css`
      display: inline-block;  // inlink使得各个子元素平铺排列
      vertical-align: middle;
      
      // 子元素样式
      > .${itemCls} { 
        &:focus {
          z-index: 2;
        }
        &:hover {
          z-index: 3;
        }
      }
      
      // 子元素下一个兄弟,分隔符下一个子元素,子元素下一个分隔符 统一都加上左边距,这里就是space的用法
      > .${itemCls}+.${itemCls}, > .${separatorCls}+.${itemCls}, > .${itemCls}+.${separatorCls} {
        margin-left: ${space};
      }
    `;
  }),
);

复制代码

間隔定数に関しては、テーマ本体で定数を定義できます。

T_SPACING_COMMON_XS: '4px',
T_SPACING_COMMON_SM: '8px',
T_SPACING_COMMON_MD: '12px',
T_SPACING_COMMON_LG: '16px',
T_SPACING_COMMON_XLG: '20px',
T_SPACING_COMMON_XXLG: '24px',
T_SPACING_COMMON_XXXLG: '32px',
复制代码

次に、プロジェクトでそれを使用します。

<Combine>
  <Button styleType="primary">按钮组展示</Button>
  <Button>按钮组展示</Button>
  <Button>按钮组展示</Button>
  <Button disabled>按钮组展示</Button>
</Combine>
复制代码

これまでのところ、レイアウトコンポーネントBoxCombine紹介は完了しています〜その他のコンポーネントについては、コードリポジトリを参照してください:Giteeリポジトリ

参照する

Reactコンポーネントのスペースとグリッド
Antd

おすすめ

転載: juejin.im/post/7082686023213252616