React-布局组件

395 阅读2分钟

背景

因部分页面重复性样式较多,出于开发效率及后期维护考虑决定将其提取为布局组件从而提高开发效率降低后期维护成本。

需求

如下图所示,该组件主要分为三个模块,分别为左-中-右,每个视图区域超出可视范围可进行滚动。布局组件的实现主要在于样式的配置,组件中的内容可自定义。

8cd2e6b608d8b08680a2fe890b00d4d.png

实现

// 使用示例
<Layout>
  <LayoutLeft>xxx</LayoutLeft>
  <LayoutCenter>xxx</LayoutCenter>
  <LayoutRight>xxx</LayoutRight>
</Layout>
// Layout
import styles from './index.less';
interface layoutProps {
  /**
   * 视图内容
   */
  children: any;
  /**
   * 类型
   */
  type?: string;
  /**
   * ref
   */
  paneRef?: any;
  /**
   * 自定义样式
   */
  style?: any;
}
const Index = (props: layoutProps) => {
  const { children, type, paneRef, style } = props;
  return (
    <div
      style={style}
      ref={paneRef}
      className={type === 'single' ? styles.singleLayout : styles.layout}
    >
      {children}
    </div>
  );
};
export default Index;

// LayoutLeft
import styles from './index.less';

const Index = (props: any) => {
  const { children } = props;
  return <div className={styles.left}>{children}</div>;
};
export default Index;
// LayoutCenter
import styles from './index.less';

const Index = (props: any) => {
  const { children } = props;
  return <div className={styles.center}>{children}</div>;
};
export default Index;
// LayoutRight
import styles from './index.less';

const Index = (props: any) => {
  const { children } = props;
  return <div className={styles.right}>{children}</div>;
};
export default Index;

// 总布局
.layout {
  display: flex;
  width: 100%;
  height: 100%;
  overflow: hidden;

  :global {
    .ant-divider-horizontal.ant-divider-with-text::after {
      border-top-color: @field-border-color;
    }

    .ant-divider {
      border-top-color: @field-border-color;
    }

    .@{ant-prefix}-anchor-link-title {
      color: @form-label-text-color  !important;
      font-size: 14px !important;
    }

    .@{ant-prefix}-input-number-sm {
      width: 100%;
    }

    .@{ant-prefix}-divider-horizontal.@{ant-prefix}-divider-with-text {
      margin: 0;
      padding: 16px 0;
    }

    .@{ant-prefix}-input-group-addon {
      color: #000;
    }

    .@{ant-prefix}-divider-horizontal.@{ant-prefix}-divider-with-text-left::before {
      width: 0;
    }

    .@{ant-prefix}-divider-inner-text {
      font-weight: 700;
      color: @primary-text-color;
      font-size: 14px;
      padding-left: 0;
    }

    .@{ant-prefix}-input-number-group-wrapper {
      width: 100%;
    }

    .@{ant-prefix}-affix {
      top: 70px !important;
    }
  }
}

.singleLayout {
  width: 100%;
  height: 100%;
  overflow: hidden;
  padding: 16px 24px 0;

  :global {
    .ant-divider-horizontal.ant-divider-with-text::after {
      border-top-color: @field-border-color;
    }

    .ant-divider {
      border-top-color: @field-border-color  !important;
    }

    .@{ant-prefix}-input-group-addon {
      color: @primary-text-color;
    }

    .@{ant-prefix}-divider-horizontal.@{ant-prefix}-divider-with-text-left::before {
      width: 0;
    }

    .@{ant-prefix}-divider-inner-text {
      font-weight: 700;
      color: @primary-text-color;
      font-size: 14px;
      padding-left: 0;
    }

    .@{ant-prefix}-anchor-link-title {
      color: @form-label-text-color;
    }

    // .@{ant-prefix}-anchor-link-title-active {
    //   color: #333;
    //   font-weight: 700;
    // }

    .@{ant-prefix}-input-number-group-wrapper {
      width: 100%;
    }

    .@{ant-prefix}-affix {
      top: 70px !important;
    }
  }
}

// 锚点区域
.left {
  // padding: 0 21px 0 9px;
  font-size: 14px;
  border-right: 1px solid @field-border-color;
}

// 中间内容区
.center {
  flex: 1;
  overflow: auto;
  padding: 0 24px;
  overflow-y: auto;
}

// 右边内容区
.right {
  border-left: 1px solid @field-border-color;
  background-color: @tab-background-color;
  width: 290px;
  overflow: auto;
  padding: 0 16px;
}