Ant-design 源码分析之数据展示(六)Collapse
2021SC@SDUSC
一、组件结构
1、ant代码结构
2、组件结构
ant中Collapse的index.tsx中引入了Collapse和CollapsePanel。
引用rc-collapse。
二、antd组件调用关系
1、Collapse.tsx
导入相应模块以及相应的ICON图标
import * as React from 'react';
import RcCollapse from 'rc-collapse';
import {
CSSMotionProps } from 'rc-motion';
import classNames from 'classnames';
import RightOutlined from '@ant-design/icons/RightOutlined';import toArray from 'rc-util/lib/Children/toArray';
import omit from 'rc-util/lib/omit';
import CollapsePanel, {
CollapsibleType } from './CollapsePanel';
import {
ConfigContext } from '../config-provider';
import collapseMotion from '../_util/motion';
import {
cloneElement } from '../_util/reactNode';
声明CollapseProps接口
export type ExpandIconPosition = 'left' | 'right' | undefined;export interface CollapseProps {
activeKey?: Array<string | number> | string | number;defaultActiveKey?: Array<string | number> | string | number;accordion?: boolean;destroyInactivePanel?: boolean;onChange?: (key: string | string[]) => void;style?: React.CSSProperties;className?: string;bordered?: boolean;prefixCls?: string;expandIcon?: (panelProps: PanelProps) => React.ReactNode;expandIconPosition?: ExpandIconPosition;ghost?: boolean;collapsible?: CollapsibleType;
}
accordion:手风琴模式,每次只打开一个tab,类型为boolean
activeKey:当前激活 tab 面板的 key,类型为string[] | string number[] | number
bordered:带边框风格的折叠面板,类型为boolean
collapsible:所有子面板是否可折叠或指定可折叠触发区域,类型为header | disabled
defaultActiveKey:初始化选中面板的 key,类型为string[] | string number[] | number
destroyInactivePanel:销毁折叠隐藏的面板,类型为boolean
expandIcon:自定义切换图标,类型为(panelProps) => ReactNode
expandIconPosition:设置图标位置,类型为left | right
ghost:使折叠面板透明且无边框,类型为boolean
onChange:切换面板的回调,类型为function
interface PanelProps {
isActive?: boolean;header?: React.ReactNode;className?: string;style?: React.CSSProperties;showArrow?: boolean;forceRender?: boolean;/** @deprecated Use `collapsible="disabled"` instead */disabled?: boolean;extra?: React.ReactNode;collapsible?: CollapsibleType;
}interface CollapseInterface extends React.FC<CollapseProps> {
Panel: typeof CollapsePanel;
}
const Collapse: CollapseInterface = props => {
const {
getPrefixCls, direction } = React.useContext(ConfigContext);const {
prefixCls: customizePrefixCls, className = '', bordered = true, ghost } = props;const prefixCls = getPrefixCls('collapse', customizePrefixCls);
//获取图片位置const getIconPosition = () => {
const {
expandIconPosition } = props;if (expandIconPosition !== undefined) {
return expandIconPosition;}return direction === 'rtl' ? 'right' : 'left';};
自定义切换图标
const renderExpandIcon = (panelProps: PanelProps = {
}) => {
const {
expandIcon } = props;const icon = (expandIcon ? (expandIcon(panelProps)) : (<RightOutlined rotate={
panelProps.isActive ? 90 : undefined} />)) as React.ReactNode;return cloneElement(icon, () => ({
className: classNames((icon as any).props.className, `${
prefixCls}-arrow`),}));};
const iconPosition = getIconPosition();const collapseClassName = classNames({
[`${
prefixCls}-borderless`]: !bordered,[`${
prefixCls}-icon-position-${
iconPosition}`]: true,[`${
prefixCls}-rtl`]: direction === 'rtl',[`${
prefixCls}-ghost`]: !!ghost,},className,);const openMotion: CSSMotionProps = {
...collapseMotion,motionAppear: false,leavedClassName: `${
prefixCls}-content-hidden`,};
获取默认折叠面板
const getItems = () => {
const {
children } = props;return toArray(children).map((child: React.ReactElement, index: number) => {
if (child.props?.disabled) {
const key = child.key || String(index);const {
disabled, collapsible } = child.props;const childProps: CollapseProps & {
key: React.Key } = {
...omit(child.props, ['disabled']),key,collapsible: collapsible ?? (disabled ? 'disabled' : undefined),};return cloneElement(child, childProps);}return child;});};return (<RcCollapseopenMotion={
openMotion}{
...props}expandIcon={
renderExpandIcon}prefixCls={
prefixCls}className={
collapseClassName}>{
getItems()}</RcCollapse>);
};
2、CollapsePanel.tsx
导入相应模块以及相应的ICON图标
import * as React from 'react';
import RcCollapse from 'rc-collapse';
import classNames from 'classnames';
import {
ConfigContext } from '../config-provider';
import devWarning from '../_util/devWarning';
声明CollapsePanelProps接口
//是否可折叠
export type CollapsibleType = 'header' | 'disabled';export interface CollapsePanelProps {
key: string | number;header: React.ReactNode;/** @deprecated Use `collapsible="disabled"` instead */disabled?: boolean;className?: string;style?: React.CSSProperties;showArrow?: boolean;prefixCls?: string;forceRender?: boolean;id?: string;extra?: React.ReactNode;collapsible?: CollapsibleType;
}
collapsible:是否可折叠或指定可折叠触发区域,类型为header | disabled
extra:自定义渲染每个面板右上角的内容,类型为ReactNode
forceRender:被隐藏时是否渲染 DOM 结构,类型为boolean
header:面板头内容,类型为ReactNode
key:对应 activeKey,类型为string | number
showArrow:是否展示当前面板上的箭头,类型为boolean
实现类
const CollapsePanel: React.FC<CollapsePanelProps> = props => {
devWarning(!('disabled' in props),'Collapse.Panel','`disabled` is deprecated. Please use `collapsible="disabled"` instead.',);const {
getPrefixCls } = React.useContext(ConfigContext);const {
prefixCls: customizePrefixCls, className = '', showArrow = true } = props;const prefixCls = getPrefixCls('collapse', customizePrefixCls);const collapsePanelClassName = classNames({
[`${
prefixCls}-no-arrow`]: !showArrow,},className,);return <RcCollapse.Panel {
...props} prefixCls={
prefixCls} className={
collapsePanelClassName} />;
};