zarm-web
Version:
基于 React 的桌面端UI库
154 lines (133 loc) • 3.95 kB
JavaScript
import React, { Component, createRef } from 'react';
const percent = 0.06;
export default class CollapseTransition extends Component {
constructor(...args) {
super(...args);
this.collapseWrap = createRef();
}
componentDidMount() {
const {
visible
} = this.props;
this.beforeEnter();
if (visible) {
this.enter();
}
}
componentDidUpdate(props) {
const {
visible
} = this.props;
if (visible !== props.visible) this.triggerChange(visible);
}
componentWillUnmount() {
this.beforeLeave();
this.leave();
}
triggerChange(visible) {
if (visible) {
this.beforeEnter();
this.enter();
} else {
this.beforeLeave();
this.leave();
}
}
beforeEnter() {
const el = this.collapseWrap.current;
el.dataset.oldPaddingTop = el.style.paddingTop;
el.dataset.oldPaddingBottom = el.style.paddingBottom;
el.dataset.oldOverflow = el.style.overflow;
el.style.height = 0;
el.style.paddingTop = 0;
el.style.paddingBottom = 0;
}
enter() {
const el = this.collapseWrap.current;
let tempHeight = 0;
let tempPaddingTop = 0;
let tempPaddingBottom = 0;
el.style.display = 'block';
function step(context) {
tempHeight = Math.min(el.scrollHeight, tempHeight += el.scrollHeight * percent);
tempPaddingTop = Math.min(el.dataset.oldPaddingTop, tempPaddingTop += el.dataset.oldPaddingTop * percent);
tempPaddingBottom = Math.min(el.dataset.oldPaddingBottom, tempPaddingBottom += el.dataset.oldPaddingBottom * percent);
el.style.height = `${tempHeight}px`;
el.style.paddingTop = tempPaddingTop;
el.style.paddingBottom = tempPaddingBottom;
if (tempHeight < el.scrollHeight) {
requestAnimationFrame(() => {
step(context);
});
} else {
context.afterEnter();
}
}
requestAnimationFrame(() => {
step(this);
});
el.style.overflow = 'hidden';
}
afterEnter() {
const el = this.collapseWrap.current;
el.style.display = 'block';
el.style.height = '';
el.style.overflow = el.dataset.oldOverflow;
}
beforeLeave() {
const el = this.collapseWrap.current;
el.dataset.oldPaddingTop = el.style.paddingTop;
el.dataset.oldPaddingBottom = el.style.paddingBottom;
el.dataset.oldOverflow = el.style.overflow;
el.style.display = 'block';
if (el.scrollHeight !== 0) {
el.style.height = `${el.scrollHeight}px`;
}
el.style.overflow = 'hidden';
}
leave() {
const el = this.collapseWrap.current;
let tempHeight = el.scrollHeight;
let tempPaddingTop = el.dataset.oldPaddingTop;
let tempPaddingBottom = el.dataset.oldPaddingBottom;
function step(context) {
tempHeight = Math.max(0, tempHeight -= el.scrollHeight * percent);
tempPaddingTop = Math.max(0, tempPaddingTop -= el.dataset.oldPaddingTop * percent);
tempPaddingBottom = Math.max(0, tempPaddingBottom -= el.dataset.oldPaddingBottom * percent);
el.style.height = `${tempHeight}px`;
el.style.paddingTop = tempPaddingTop;
el.style.paddingBottom = tempPaddingBottom;
if (tempHeight !== 0) {
requestAnimationFrame(() => {
step(context);
});
} else {
context.afterLeave();
}
}
requestAnimationFrame(() => {
step(this);
});
}
afterLeave() {
const el = this.collapseWrap.current;
if (!el) return;
el.style.display = 'none';
el.style.height = '';
el.style.overflow = el.dataset.oldOverflow;
el.style.paddingTop = el.dataset.oldPaddingTop;
el.style.paddingBottom = el.dataset.oldPaddingBottom;
}
render() {
const {
children
} = this.props;
return React.createElement("div", {
className: "collapse-transition",
ref: this.collapseWrap,
style: {
overflow: 'hidden'
}
}, children);
}
}