点击在线浏览,体验更好链接
古代JavaScript高级小册链接
深入浅出Dart链接
古代TypeScript高级小册链接

jcode

咱们先从最根本的实现开始,而后逐渐增加更多的性能,如手风琴模式、自定义箭头、禁用状态、暗藏时是否渲染DOM构造

组件接口定义

Collapse

属性阐明类型默认值
accordion是否开启手风琴模式booleanfalse
activeKey以后开展面板的 key手风琴模式:string \null 非手风琴模式:string[]-
arrow自定义箭头,如果是 ReactNode,那么 antd-mobile 会主动为你减少旋转动画成果ReactNode \((active: boolean) => React.ReactNode)-
defaultActiveKey默认开展面板的 key手风琴模式:string \null 非手风琴模式:string[]-
onChange切换面板时触发手风琴模式:(activeKey: string \null) => void 非手风琴模式:(activeKey: string[]) => void-

Collapse.Panel

属性阐明类型默认值
arrow自定义箭头ReactNode \((active: boolean) => React.ReactNode)-
destroyOnClose不可见时卸载内容booleanfalse
disabled是否为禁用状态booleanfalse
forceRender被暗藏时是否渲染 DOM 构造booleanfalse
key惟一标识符string-
onClick标题栏的点击事件(event: React.MouseEvent<Element, MouseEvent>) => void-
title标题栏左侧内容ReactNode-

创立根底Collapse组件

咱们创立一个根底的Collapse组件。这个组件须要有一个状态来追踪它是否被开展

import React, { useState } from 'react';const Collapse = ({ children }) => {  const [isOpen, setIsOpen] = useState(false);  return (    <div>      <button onClick={() => setIsOpen(!isOpen)}>        {isOpen ? 'Collapse' : 'Expand'}      </button>      {isOpen && <div>{children}</div>}    </div>  );};export default Collapse;

拓展Collapse组件其它属性

  • accordion:如果设置为true,咱们将启用手风琴模式。在这种模式下,只有一个面板能够被开展。当一个新的面板被开展时,之前开展的面板将被敞开。
  • activeKey:这是以后开展面板的key。如果咱们处于手风琴模式,这将是一个字符串或null。如果咱们不在手风琴模式,这将是一个字符串数组。
  • arrow:这是一个自定义的箭头。如果这是一个React节点,antd-mobile将主动为你增加旋转动画成果。如果这是一个函数,它将接管一个参数,示意面板是否被开展,并返回一个React节点。
  • defaultActiveKey:这是默认开展面板的key。它的类型与activeKey雷同。
  • onChange:这是一个函数,它在面板切换时被触发。它接管一个参数,示意以后开展面板的key。它的类型与activeKey雷同。
import React, { useState, useEffect } from 'react';const Collapse = ({ children, forceRender, accordion, activeKey, arrow, defaultActiveKey, onChange }) => {  const [isOpen, setIsOpen] = useState(false);  const [currentActiveKey, setCurrentActiveKey] = useState(defaultActiveKey);  useEffect(() => {    setCurrentActiveKey(activeKey);  }, [activeKey]);  const handleClick = () => {    setIsOpen(!isOpen);    if (accordion) {      setCurrentActiveKey(isOpen ? null : activeKey);    }    onChange && onChange(isOpen ? null : activeKey);  };  const renderArrow = () => {    if (typeof arrow === 'function') {      return arrow(isOpen);    }    return arrow;  };  return (    <div>      <button onClick={handleClick}>        {isOpen ? 'Collapse' : 'Expand'}        {renderArrow()}      </button>      <div style={{ display: isOpen || forceRender ? 'block' : 'none' }}>        {children}      </div>    </div>  );};export default Collapse;

实现Panel

咱们创立一个名为Collapse.Panel的子组件来反对这些新的属性。这个子组件将作为Collapse组件的一部分,用于示意一个可折叠的面板。

  • arrow:这是一个自定义的箭头。如果这是一个React节点,antd-mobile将主动为你增加旋转动画成果。如果这是一个函数,它将接管一个参数,示意面板是否被开展,并返回一个React节点。
  • destroyOnClose:如果设置为true,咱们将在面板敞开时销毁它的内容。
  • disabled:如果设置为true,咱们将禁用面板,使其不能被关上或敞开。
  • forceRender:如果设置为true,咱们将在面板敞开时依然渲染它的DOM构造。
  • key:这是面板的惟一标识符。
  • onClick:这是一个函数,它在面板的标题栏被点击时被触发。它接管一个参数,示意点击事件。
  • title:这是面板标题栏的内容。
import React, { useState, useEffect } from 'react';const Panel = ({ children, arrow, destroyOnClose, disabled, forceRender, key, onClick, title }) => {  const [isOpen, setIsOpen] = useState(false);  const handleClick = (event) => {    if (disabled) return;    setIsOpen(!isOpen);    onClick && onClick(event);  };  const renderArrow = () => {    if (typeof arrow === 'function') {      return arrow(isOpen);    }    return arrow;  };  useEffect(() => {    if (destroyOnClose && !isOpen) {      children = null;    }  }, [isOpen]);  return (    <div key={key}>      <button onClick={handleClick}>        {title}        {renderArrow()}      </button>      <div style={{ display: isOpen || forceRender ? 'block' : 'none' }}>        {children}      </div>    </div>  );};const Collapse = ({ children, accordion, activeKey, defaultActiveKey, onChange }) => {};Collapse.Panel = Panel;export default Collapse;

forceRender属性

咱们要增加一个名为forceRender的属性。如果这个属性被设置为true,咱们会在组件暗藏时依然渲染DOM构造,如果面板渲染的数据量比拟大,这个属性特地有用,不会造成关上的时候会卡顿一下
import React, { useState } from 'react';const Collapse = ({ children, forceRender }) => {  const [isOpen, setIsOpen] = useState(false);  return (    <div>      <button onClick={() => setIsOpen(!isOpen)}>        {isOpen ? 'Collapse' : 'Expand'}      </button>      <div style={{ display: isOpen || forceRender ? 'block' : 'none' }}>        {children}      </div>    </div>  );};export default Collapse;

实现折叠面板动画

height形式实现

.collapse-panel {  border: 1px solid #ddd;  border-radius: 4px;  margin-bottom: 10px;  overflow: hidden;}.collapse-panel-button {  background-color: #f5f5f5;  color: #333;  cursor: pointer;  padding: 10px 15px;  width: 100%;  text-align: left;  border: none;  outline: none;}.collapse-panel-content {  padding: 10px 15px;  background-color: white;  overflow: hidden;  max-height: 0;  transition: max-height 0.2s ease-out;}.collapse-panel-content.open {  max-height: 100vh;}
import React, { useState, useEffect, useRef } from 'react';const Panel = ({ children, arrow, destroyOnClose, disabled, forceRender, key, onClick, title }) => {  const [isOpen, setIsOpen] = useState(false);  const contentRef = useRef(null);  const handleClick = (event) => {    if (disabled) return;    setIsOpen(!isOpen);    onClick && onClick(event);  };  const renderArrow = () => {    if (typeof arrow === 'function') {      return arrow(isOpen);    }    return arrow;  };  useEffect(() => {    if (destroyOnClose && !isOpen) {      children = null;    }  }, [isOpen]);  useEffect(() => {    contentRef.current.style.maxHeight = isOpen ? `${contentRef.current.scrollHeight}px` : '0';  }, [isOpen]);  return (    <div key={key} className="collapse-panel">      <button onClick={handleClick} className="collapse-panel-button">        {title}        {renderArrow()}      </button>      <div ref={contentRef} className={`collapse-panel-content ${isOpen ? 'open' : ''}`}>        {children}      </div>    </div>  );};// ...

残缺成果:
jcode

其它形式

下面手风琴成果是利用height的实现,这种实现会触发重排,所以感兴趣的同学能够思考其它形式优化一下
  • 基于scaleY
  • 应用FLIP技术增加动画优化