持续更新ing...
安装dumi
官网:d.umijs.org/guide/initi…
安装npx create-dumi
搭建组件库选择 React Library
,否则在 md
文件写组件demo
文档是没办法生效的。React Library
就是说你想开发一个以 React
为基础的库,dumi
对md
文档输出进行特殊的处理。
配置完成后文件列表
设置logo等基础配置
在.dumirc.ts
中配置主题颜色、图标等:
docs
文件用于配置网页展示内容,用md
格式编写
组件编写
在src
文件中做基本配置
button编写
index.ts
统一导出组件
themeStyles
文件定义一些常用主题颜色
一个普通组件的文件构成:
index.ts
来编写组件
md
文件负责文档的展示,使用<code>
标签引入demo中的代码展示
demo
文件包含要在文档中展示的例子,在头部注释写title,description
dumi会自动解析。
效果:
style
文件包含该组件对应的样式,引入我们编写的主题样式,使用@import url(../..)
样式来引入
each
遍历
dropdown下拉框编写
使用rc-trigger
进行二次开发。
有两个必要属性:1.{children必要}2.popup
弹出层内容必要
import React from 'react';
import Trigger from 'rc-trigger';
const MyPopup = () => {
return <div>这里是弹出层的内容</div>;
};
const ExampleComponent = () => {
return (
<Trigger popup={<MyPopup />}>
<button>点击触发弹出层</button>
</Trigger>
);
};
scope布局编写
使用到了一个自己不熟悉的知识:React.Children
是React
提供的一个用于处理React
元素的方法。其中callback
接收到两个参数child
和index
。
React.Children.map(children,callback)
对每个子元素调用回调函数,并返回一个新数组。React.Children.forEach(children,callback)
对每个子元素掉用回调函数,没有返回值。React.Children.count(children)
返回子元素数量。React.Children.only(children)
验证子元素只有一个,并返回该子元素。React.Children.toArray
将子元素转换成一个数组。
Alert警示框编写
浮层元素是指在网页或应用程序中以覆盖式展示,并且需要用户进行操作才能关闭的UI组件。通常,浮层元素会在当前页面的顶部弹出一个层级较高的容器,使用户无法与页面的其他内容进行交互,直到浮层关闭或完成相应操作。
描述:用于页面展示重要的提示消息。Alert
组件不属于浮层元素,不会自动消失或关闭。
样式CSS:width:max-content
元素会根据其内容宽度自动扩展(不受限于父元素宽度或其他因素)
drawer抽屉
点击一个按钮,从屏幕边缘滑出浮层面板。需要点击遮罩区或者“x”图标来关闭。
改变open来控制wrapper组件显示与隐藏,open也控制遮罩层是否显示。open和masked初始值都是false。这里打印的open是最新改变的值,但打印的masked是原始记忆值。
如果动画不生效,考虑是否因为其他元素覆盖。
modal对话框
react-transition-group
库(有三个可以引用:CSSTransition
控制显示与隐藏、SwitchTransition
控制内容切换、TransitionGroup
控制列表)。使用SwitchTransition
包裹CSSTransition
。这个库让动画效果的完成方便很多。
引入:import {CSSTransition} from 'react-transition-group'
使用:
<CSSTransition className='cherry-modal-mask' in={masked} timeout={300}>
<div className="modal-mask"></div>
</CSSTransition>
in
是触发条件,timeout
是持续时间。
具体CSS代码编写:
// 动画编写--直接绑定在指定元素上了。
.cherry-modal-mask-enter {
opacity: 0;
}
.cherry-modal-mask-active {
opacity: 1;
transition: opacity 300ms;
}
.cherry-modal-mask-enter-done,
.cherry-modal-mask-exit {
opacity: 1;
}
.cherry-modal-mask-exit-active {
opacity: 0;
transition: opacity 300ms;
}
默认页脚按钮定义:
// footer按钮类型--定义一个对象包含两个模式(即default和simple,他们的值都是ReactNode)
const buttonArea: {default:ReactNode;simple:ReactNode} = {
default:(
<>
<span className="footer-item" onClick={onCancel}>
<Button >取消</Button>
</span>
<span className="footer-item" onClick={onCancel}>
<Button >确定</Button>
</span>
</>
),
simple:(
<>
<span className="footer-item" onClick={onCancel}>
<Button >知道了</Button>
</span>
</>
)
}
应用:
<footer className="modal-footer">
{// 如果有自定义页脚footerItem则用自定义,没有则使用我们默认的type
footerItem?footerItem.map((item,index)=>{
return (
<span className="footer-item" key={index}>
{item}
</span>
)
}):buttonArea[footerType]
}
</footer>
??
是空值合并运算符(nullish coalescing operator)。它的作用是判断左侧的操作数是否为 null 或 undefined,如果是,则返回右侧的操作数。否则,返回左侧的操作数。
待完成:键盘退出
menu菜单
在index.tsx中定义MenuContext
并暴露。使用createContext
定义一个名为MenuContext
的上下文对象,这个上下文的初始值是一个实现了MenuContext
接口的对象,其中index
属性被设置为0。导出这个上下文对象,其他模块可以引入并使用这个上下文对象来共享数据。
import React, { createContext } from 'react';
interface IMenuContext {
index:string;
onSelect?:(selectedIndex: string) => void;
mode?:'horizontal' | 'vertical';
defaultOpenSubMenus?:string[];
}
export const MenuContext = createContext<IMenuContext>({index:'0'})
return (
<ul className={classes}>
<MenuContext.Provider value={passedContext}>
{childrenRender()}
</MenuContext.Provider>
</ul>
)
在其他模块中引入并使用
import React, { useContext } from "react";
import { MenuContext } from ".";
const context = useContext(MenuContext)
在index.tsx文件中循环遍历menuItem
加工生成对应的元素
const childrenRender = () => {
return React.Children.map(children,(child,index)=>{
const childElement = child as React.FunctionComponentElement<MenuItemProps>
console.log(childElement);
const {displayName} = childElement.type//解构幅值
if(displayName == 'MenuItem'){
return React.cloneElement(childElement,{
index: index.toString(),
})
}else{
return <Alert title="警告提示" type="warning" closeable={true}>Menu has a child which is not a MenuItem component</Alert>
}
})
}
打印一下childrenElement
clone处理之后加入index属性的childrenElement
childrenElement.type都是MenuItemProps中的定义
React.cloneElement
是 React 提供的一个函数,用于克隆并返回一个已有的 React 元素,并可以传递新的属性给克隆后的元素。
其语法如下:
jsxCopy Code
React.cloneElement(element, props, ...children)
element
:要克隆的 React 元素。props
:要添加或替换的新属性对象。...children
:可选参数,额外的子元素。 所以父组件给子组件加了index属性并传递index(通过cloneElement),子组件中调用留在父组件的回调函数来更新index。
subMenuItem
二级菜单,title
是一级菜单名,里面遍历生成带有xx-xx
的index
。
const renderChildren = () => {
const subMenuClasses = classNames('cherry-submenu', {
'menu-opened': menuOpen,
'cherry-submenu-vertical': context.mode == 'vertical',
'submenu-item-horizontal': context.mode !== 'vertical'
})
// 循环遍历生成带有index属性的元素
const childrenComponent = React.Children.map(children, (child, i) => {
const childElement = child as FunctionComponentElement<MenuItemProps>
if (childElement.type.displayName == 'MenuItem') {
return React.cloneElement(childElement, {
index: `${index}-${i}`
})
} else {
console.error('Menu has a child which is not a MenuItem component')
}
})
// 返回子菜单
return (
<>{ menuOpen && (<CSSTransition in={menuOpen} timeout={300} classNames='cherry-subMenu-ul'>
<ul className={subMenuClasses}>
{childrenComponent}
</ul>
</CSSTransition>)}</>
)
}
breadcrumb面包屑
a
标签的target
控制是否在当前页面跳转链接,默认_self
在当前页面打开,_blank
在新标签页面打开。
const Breadcrumb:React.FC<BreadcrumbProps> = (props)=>{
const {objects, target='_self', ...restProps} = props;
return (
<div className='cherry-breadcrumb' {...restProps}>
<ul className='breadcrumb-ul'>
{objects?.map((obj,index)=>{
return (
<>
<li key={index} className='breadcrumb-li'>
<a href={obj.link} target={target}>{obj.text}</a>
</li>
{index !== objects.length-1 && <li className='breadcrumb-li'>/</li>}
</>
)
})}
</ul>
</div>
)
}
input输入框
类名为icon-wrapper
元素的下一个兄弟元素input-inner
(紧挨)
.icon-wrapper+.input-inner {
padding-right: 35px;
}
outline: 0;
是一种 CSS 属性,用于移除元素获取焦点时的默认轮廓样式。在某些浏览器中,当元素获得焦点时,会出现一个默认的轮廓样式,通常是蓝色阴影或边框。
/* 移除所有元素的焦点轮廓 */ *
{ outline: 0; }
/* 移除特定元素的焦点轮廓 */
input:focus, button:focus { outline: 0; }
<input placeholder="请输入">
,占位文本的样式用input{&::placeholder}
伪元素选择。
没有空格--多类名选择器
有空格--父子选择器
tree
store
设置一个store文件夹,包含index.tsx和node.tsx文件。
node.tsx
node.tsx文件主要定义NodeOptions
和Node
类
定义node上的属性
如果没有子节点,那么自己选中了就是返回true,如果有子节点,每个子节点都选中了则返回true。
半选:在没有没全选中的情况下,有子节点被选中/半选中,则返回true。
自上向下来更新:选中/取消了父节点,要更新它下方所有子节点的状态。自下向上来更新:选中/取消了子节点,要更新它上方所有父节点的状态。
store的accordion来控制是否只能展开一个节点。如果为true的话则判断,flase的话传入什么就设置这个node的collapse是什么。
封装子节点。还是采用dfs形式。比index.ts中的createTree
多了判断append
的步骤。
追加和删除子节点
index.tsx
Record
接受两个类型参数 K
和 T
,其中 K
是一个键的集合(通常是字符串字面量类型或联合类型),T
是对应键的值的类型。返回的类型是一个对象,其键是 K
中的每个元素,值的类型是 T
。
创建根节点/子节点的方法,都要把store的值绑定成当前Store实例,即当前的
Store
实例作为 store
属性的值赋给新创建的 Node
对象。Omit<A,B>
表示从原始类型A中排除B属性。
递归dfs创建树
拍平数组(把children拍平)
激活node的checked属性。
new Map()
可以接收一个伪数组作为参数,例如[[1,1],[2,3]]就是1->1,2->3。
基本一样的逻辑。
index.tsx
使用useState
和useEffect
配合,当data
改变时重新构建树,当tree
改变时重新创建拍平的树的列表。新建一个传入data
的store
实例来控制状态。
根据初始化的默认点击/打开来调用store中的方法
判断一个节点是否展示,取决于它的父节点(祖先节点)的
collapse
,如果设置为false则不显示(有一个折叠就是折叠了),如果遍历到最上面的父节点都是设置为展开则该节点是显示的。
自适应高度功能。
MutationObserver
是一个在 JavaScript 中用于监测 DOM 变化的接口。它可以观察指定的 DOM 元素或 DOM 树的变化,并在变化发生时触发回调函数执行相应的操作。
MutationObserver
的常用方法和属性有:
observe(target, options)
: 启动对目标元素的观察。target
参数指定要观察的 DOM 元素,而options
参数是一个配置对象,用于指定观察的类型(如子节点变化、属性变化等)。通过此方法开启观察后,MutationObserver
会在目标元素变化时触发回调函数。disconnect()
: 停止对目标元素的观察。调用该方法后,MutationObserver
将不再触发回调函数,并且不再监听任何 DOM 变化。takeRecords()
: 返回当前已观察到但尚未处理的所有 DOM 变化记录的数组。observe(...)
方法的返回值是一个MutationObserver
实例,可以使用此实例的其他方法和属性。
在给定的代码中,MutationObserver
被用来监测 treeRef.current
的父元素的变化。具体来说,它会检测父元素的子节点变化以及子树中任何节点的变化。一旦变化发生,回调函数将被触发,并执行相应的操作。
offsetHeight
是元素的实际高度,经常用于动态布局、元素定位和响应式设计。把元素实际的高度定义给这个元素达到自适应高度的效果。
创建treeNode。
创建每个小li作为node节点。用
style
来控制节点的显示与隐藏(showNode函数的返回结果)。缩进是根据node.depth
来调节。设计一个标签来控制左边箭头的显示与隐藏。点击箭头,这个node的collapse取反,重新构建树。点击CheckBox的checked是根据node.checked设置的,点击则调用node绑定的setChecked
方法,实现父节点和子节点对应的更新。
最后把拍平树的结果过滤一遍showNode作为中的itemData。
<FixedSizeList>
是由 react-window
库提供的一个组件,用于高效地渲染大量数据时进行虚拟化。它可以帮助优化性能,减少内存消耗,并提供平滑的滚动体验。通过将 itemCount
属性设置为渲染项的总数,再结合 itemData
、itemSize
和 innerElementType
等属性,<FixedSizeList>
将仅渲染可见区域的项,而不是一次渲染整个列表。这种虚拟化的方式使得在处理大数据集时能够显著提高性能和响应速度。