封装react组件库之Collapse

2023-10-22 06:50
文章标签 react 封装 组件 collapse

本文主要是介绍封装react组件库之Collapse,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

Collapse组件折叠板

在后台系统中这个应该还是很常见用的可能不是很频繁,但是有时候还是很有适用的场景的,现在我们就来从零封装一个完整的Collapse组件。
这个是我封装好了的一个成品。我们封装组件第一步就要先去思考,

第一这个组件需要什么样的功能。
第二这个组件的一个功能确定了这个组件的代码结构,也就是常说的dom结构。
第三开始思考两小时,然后我们开始代码编写。

在之前的组件封装中我也提到过,有兴趣可以去看看我的博客其余文章,很多的组件封装我都会分享出来。
在这里插入图片描述
看到这样的结构我们这样的老油条前端大致心里面就有一个结构了:

//content
<div>
//contentItem<div>//contentItem header<div><span></span><span></span></div>//contentItem content<div></div></div><div>

这就是一个大致的dom结构了,我们在使用市面上的Collapse组件的时候很多时候都是这样

<Collapse><Panel></Panel>
</Collapse>

在组件中我们都说一个组件化组件化,意思就是能尽可能抽成组件复用的我们都会抽成一个组件。在这里我们就可以把content抽成一个Collapse组件然后把contentItem抽成一个Panel组件。
这个就是Collapse的组件代码,很简单没有特别的复杂代码,props.children传递参数在我之前的博客我也有一篇拿来专门讲过,有兴趣的可以去看看。

/** @Date: 2023-08-21 13:40:50* @Auth: 463997479@qq.com* @LastEditors: 463997479@qq.com* @LastEditTime: 2023-08-22 16:21:33* @FilePath: \reactui\src\Collapse\index.tsx*/
import classNames from 'classnames';
import React, { forwardRef, useState } from 'react';
import Panel from './Panel';type CollapseType = {children?: any;defaultKey?: string | string[] | number | number[];accordion?: boolean;onChange?: (arg: string | number | string[] | number[]) => void;className?: string;expandIconPosition?: string;collapseable?: string;
};const Collapse: React.FC<CollapseType> = forwardRef((props, ref) => {const {children,defaultKey = [],accordion = false,onChange,className,expandIconPosition = 'start',collapseable = false,} = props;const contentClass = classNames('collapse-content', className, {[`collapse-content-${expandIconPosition}`]: expandIconPosition,});const [activeKey, setActiveKey] = useState<string | number | string[] | number[]>(defaultKey ?? '');const handleActive = (arg: string | number) => {if (Array.isArray(activeKey)) {const _value = activeKey.indexOf(arg) > -1 ? '' : arg;if (accordion) {setActiveKey(_value);onChange?.(_value);return;}let arr = [];let flag = activeKey.some((item) => item === arg);if (flag) {arr = activeKey.filter((item) => item !== arg) as string[] | number[];} else {arr = activeKey.concat([arg]) as string[] | number[];}setActiveKey(arr);onChange?.(arr);} else {setActiveKey(arg === activeKey ? '' : arg);onChange?.(arg);}};return (<><div ref={ref} className={contentClass}>{React.Children.map(children, (child) => {return React.cloneElement(child, {active: activeKey,handleActive: handleActive,});})}</div></>);
});Collapse.Panel = Panel;
Collapse.displayName = 'Collapse';
Collapse.defaultProps = {accordion: false,defaultKey: [],
};
export default Collapse;

然后就是Panel组建的封装了,这个子组件也没有太大的难度,前面我们的方案已经很清楚了所以写起来也没有太大的难度,唯一一个问题很有难度我觉得有必要拿出来单独讲一下。

css怎么给一个高度auto的dom过度高度动画?你们有没有想过这个问题去如何实现呢?如果这个问题你能有很好的解决办法那这个组件也没有太大的难度,这个组件的难度就在这个动画。

第一种:一个外部容器很大的max-height值overflow,内部容器heigh:auto;然后用过渡外部容器的动画来显示。
第二种:容器直接设置transform:scale(0);transition-origin:center top;过渡到transform:scale(1);
第三种:容器display:grid;grid-template-rows:0fr;过渡到grid-template-rows:1fr;
这些方法或多或少都有一些不足的地方。最完美的还得js。
Flip动画思想应该有了解吧。先让达到一个预期的目标比如高度然后我们就能拿到这个值,拿到了这个值我们就可以对这个制作一些动画。

这都是实现的一个方向,这个组件我也是用了Flip动画。
具体的选中这些看一下代码大致就能明白这里就不做详细的说明了。

/** @Date: 2023-08-21 13:40:50* @Auth: 463997479@qq.com* @LastEditors: 463997479@qq.com* @LastEditTime: 2023-08-22 17:04:21* @FilePath: \reactui\src\Collapse\Panel.tsx*/
import { RightOutlined } from '@ant-design/icons';
import classNames from 'classnames';
import React, { useEffect, useRef, useState } from 'react';
import { CSSTransition } from 'react-transition-group';
type PanelType = {children?: any;title?: string;activeKey: string | number;active?: string | string[];handleActive?: (arg: string | number) => void;extra?: React.ReactNode;
};const Panel: React.FC<PanelType> = (props) => {const { children, title, activeKey, active, handleActive, extra } = props;const [onlyKey, setOnlyKey] = useState<string | number>(activeKey);const [show, setShow] = useState<boolean>(false);const [domShow, setDomShow] = useState<boolean>(false);useEffect(() => {let flag =active === onlyKey ||((Array.isArray(active) && active?.indexOf(onlyKey) > -1) as boolean);setOnlyKey(activeKey);setShow(flag);}, [activeKey, active, domShow]);const contentRef = useRef();const contentClass = classNames('panel-content-item', {['panel-content-item-active']: domShow,});const wrapperClass = classNames('panel-content-item-wrapper', {['panel-content-item-wrapper-active']: domShow,});const onEnter = (el: HTMLElement) => {el.style.height = '0px';el.style.overflow = 'hidden';setDomShow(true);};const onEntering = (el: HTMLElement) => {el.style.height = el.scrollHeight + 'px';};const onEntered = (el: HTMLElement) => {el.style.transition = '';el.style.height = '';};const onExit = (el: HTMLElement) => {el.style.overflow = 'hidden';el.style.height = el.scrollHeight + 'px';};const onExiting = (el: HTMLElement) => {if (el.scrollHeight !== 0) {el.style.height = '0';}};// 为什么要加el.scrollHeight !== 0的判断呢?//试一下,如果不加这个判断,直接变化height,paddingTop,paddingBottom的值到0,这个时候,收缩时并不会有过渡动画,元素马上就消失了。//setTimeout(() => {el.style.height = 0;el.style.paddingTop = 0;el.style.paddingBottom = 0;}, 20)const onExited = (el: HTMLElement) => {el.style.transition = '';el.style.height = '';setDomShow(false);};return (<><div className={contentClass}><divonClick={() => {handleActive?.(onlyKey);}}className="collapse-header"><span className="collapse-header-img"><RightOutlined /></span><span className="collapse-header-title">{title}</span><span>{extra}</span></div><CSSTransitionin={show}onEnter={onEnter}onEntering={onEntering}onEntered={onEntered}onExit={onExit}onExiting={onExiting}onExited={onExited}classNames={'collapse'}timeout={200}><div ref={contentRef}><div className={wrapperClass}>{children}</div></div></CSSTransition></div></>);
};
export default Panel;

demo示例
在这里插入图片描述

这篇关于封装react组件库之Collapse的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/259800

相关文章

JS常用组件收集

收集了一些平时遇到的前端比较优秀的组件,方便以后开发的时候查找!!! 函数工具: Lodash 页面固定: stickUp、jQuery.Pin 轮播: unslider、swiper 开关: switch 复选框: icheck 气泡: grumble 隐藏元素: Headroom

如何在页面调用utility bar并传递参数至lwc组件

1.在app的utility item中添加lwc组件: 2.调用utility bar api的方式有两种: 方法一,通过lwc调用: import {LightningElement,api ,wire } from 'lwc';import { publish, MessageContext } from 'lightning/messageService';import Ca

vue2 组件通信

props + emits props:用于接收父组件传递给子组件的数据。可以定义期望从父组件接收的数据结构和类型。‘子组件不可更改该数据’emits:用于定义组件可以向父组件发出的事件。这允许父组件监听子组件的事件并作出响应。(比如数据更新) props检查属性 属性名类型描述默认值typeFunction指定 prop 应该是什么类型,如 String, Number, Boolean,

JavaSE——封装、继承和多态

1. 封装 1.1 概念      面向对象程序三大特性:封装、继承、多态 。而类和对象阶段,主要研究的就是封装特性。何为封装呢?简单来说就是套壳屏蔽细节 。     比如:对于电脑这样一个复杂的设备,提供给用户的就只是:开关机、通过键盘输入,显示器, USB 插孔等,让用户来和计算机进行交互,完成日常事务。但实际上:电脑真正工作的却是CPU 、显卡、内存等一些硬件元件。

kubelet组件的启动流程源码分析

概述 摘要: 本文将总结kubelet的作用以及原理,在有一定基础认识的前提下,通过阅读kubelet源码,对kubelet组件的启动流程进行分析。 正文 kubelet的作用 这里对kubelet的作用做一个简单总结。 节点管理 节点的注册 节点状态更新 容器管理(pod生命周期管理) 监听apiserver的容器事件 容器的创建、删除(CRI) 容器的网络的创建与删除

js react 笔记 2

起因, 目的: 记录一些 js, react, css 1. 生成一个随机的 uuid // 需要先安装 crypto 模块const { randomUUID } = require('crypto');const uuid = randomUUID();console.log(uuid); // 输出类似 '9b1deb4d-3b7d-4bad-9bdd-2b0d7b3dcb6d'

火语言RPA流程组件介绍--浏览网页

🚩【组件功能】:浏览器打开指定网址或本地html文件 配置预览 配置说明 网址URL 支持T或# 默认FLOW输入项 输入需要打开的网址URL 超时时间 支持T或# 打开网页超时时间 执行后后等待时间(ms) 支持T或# 当前组件执行完成后继续等待的时间 UserAgent 支持T或# User Agent中文名为用户代理,简称 UA,它是一个特殊字符串头,使得服务器

哈希表的封装和位图

文章目录 2 封装2.1 基础框架2.2 迭代器(1)2.3 迭代器(2) 3. 位图3.1 问题引入3.2 左移和右移?3.3 位图的实现3.4 位图的题目3.5 位图的应用 2 封装 2.1 基础框架 文章 有了前面map和set封装的经验,容易写出下面的代码 // UnorderedSet.h#pragma once#include "HashTable.h"

封装MySQL操作时Where条件语句的组织

在对数据库进行封装的过程中,条件语句应该是相对难以处理的,毕竟条件语句太过于多样性。 条件语句大致分为以下几种: 1、单一条件,比如:where id = 1; 2、多个条件,相互间关系统一。比如:where id > 10 and age > 20 and score < 60; 3、多个条件,相互间关系不统一。比如:where (id > 10 OR age > 20) AND sco

vue 父组件调用子组件的方法报错,“TypeError: Cannot read property ‘subDialogRef‘ of undefined“

vue 父组件调用子组件的方法报错,“TypeError: Cannot read property ‘subDialogRef’ of undefined” 最近用vue做的一个界面,引入了一个子组件,在父组件中调用子组件的方法时,报错提示: [Vue warn]: Error in v-on handler: “TypeError: Cannot read property ‘methods