80行代码实现Preact-Transition组件
80行代码实现Preact-Transition组件
Preact是3kb轻量化方案, 但是一些基础组件找起来比较困难, 用起来也比较别扭,其中一个就是Transition组件, 尝试过preact-transition-group, 但是直接npm安装使用就报错了...因为有个preact版本兼容问题
【80行代码实现Preact-Transition组件】transition.js
// 这一行代码没兼容, 新版preact children不一定是都是数组
359 -const child = children[0]
+const child = children[0] || children
360return cloneElement(child, childProps)
但是看了transition.js (391行) + CSSTransition(181行), 感觉不需要这么多行代码即可实现所需的Transition组件
并且在使用过程中timeout的配置竟是比较迷惑... 所以就有了造论子的机会了
const PopupBaseLayout = ({
children,
canClass = '',
position = 'bottom',
}) => {
const { enter, onContentExited } = useContext(PopupContext)const transProps = {
appear: true,
timeout: {
exit: 350,
enter: 1,
// appear需要配合enter timout为1ms, 弹窗动画才符合预期...
// 但是还是会偶现动画不触发的情况
},
classNames: {
enterActive: style.enter,
enterDone: style.enter,
exitActive: style.exit,
exitDone: style.exit,
},
onExited: onContentExited,
}return (
{children}
)
}
其实之前也写过弹窗过渡动画的组件, 也熟悉其生命周期, 所以简单梳理下状态变换流程就可以编写了
状态扭转也两个分支:
enter->entering->entered
exit->exiting->exited而其中4个状态的流转可以由两个变量派生出来:show 和 switching
enter/entered/exit/exited而entering则紧跟着enter, exiting则紧跟着exit状态的对应关系:
show && !switching => entered
!show && !switching => exited
show && switching => enter
!show && switching => exit剩下就是加上show变化对switching的变化即可
最终写下来只需要80行代码即可实现了
- 接口与CSSTransition类似
- 大概80行代码
- 无需设置duration, duration与transition-duration一样
- 无需繁琐设置classNames传递一个className即可, css里配合data-state来命中状态
import { useRef, useState, useEffect } from 'preact/hooks'const nop = () => {}
// 接口尽量和React CSSTransition类似
function Transition({
appear = false,
in: show = false,
unmountOnExit = false,children,
className, // 使用className+data-state组合, 方便复用onEnter = nop,
onEntering = nop,
onEntered = nop,onExit = nop,
onExiting = nop,
onExited = nop,
}) {
const canRef = useRef()
const { current: that } = useRef({ lastShow: show, switching: appear })
// Preact可以使用this, function TPL() {} 这种函数组件声明的时候, 箭头函数则不行// 触发一次更新
const [renderId, setRenderId] = useState(0)
const [domReady, setDomReady] = useState(false)// 当show变化的时候重置为switching为true
if (that.lastShow !== show) that.switching = true
that.lastShow = showconst { switching } = that
const renderDom = !(!show && !switching && unmountOnExit)let state // 根据show 和 switching 派生出 state
if (show && !switching) state = 'entered'
if (!show && !switching) state = 'exited'if (switching) {
that[show ? 'exiting' : 'entering'] = false
state = show ? 'enter' : 'exit'
domReady && show ? onEnter() : onExit()
domReady &&
requestAnimationFrame(() => {
that[show ? 'exiting' : 'entering'] = true
// 直接更新dom节点属性, 只是一帧的时间差
canRef.current &&
canRef.current.setAttribute(
'data-state',
show ? 'entering' : 'exiting',
)
show ? onEntering() : onExiting()
})
}useEffect(() => {
!domReady && requestAnimationFrame(() => setDomReady(true))
})const onTransitionEnd = e => {
if (!(e.target === canRef.current && switching)) return
that.switching = false
// 触发函数组件执行, 进而触发state的更新
setRenderId(renderId + 1)
show ? onEntered() : onExited()
}return renderDom ? ({children}) : undefined
}export default Transition
使用Preact的同学可以尝试下,
简约框架
搭配简约组件
, 这里可以体验DEMOhttps://github.com/deepkolos/pc-transition
推荐阅读
- CVE-2020-16898|CVE-2020-16898 TCP/IP远程代码执行漏洞
- 关于QueryWrapper|关于QueryWrapper,实现MybatisPlus多表关联查询方式
- MybatisPlus使用queryWrapper如何实现复杂查询
- python学习之|python学习之 实现QQ自动发送消息
- 孩子不是实现父母欲望的工具——林哈夫
- opencv|opencv C++模板匹配的简单实现
- Node.js中readline模块实现终端输入
- java中如何实现重建二叉树
- 不废话,代码实践带你掌握|不废话,代码实践带你掌握 强缓存、协商缓存!
- 人脸识别|【人脸识别系列】| 实现自动化妆