[英]Trying to emulate Bootstrap navbar collapse/expand with React State
单击汉堡图标时,我正在尝试使用 Bootstrap 展开和折叠导航栏。 问题是我正在使用 React,而且我很确定 Bootstrap 的 DOM 操作与 React 的 DOM 操作有冲突。 因此,我试图将所有操作从 Bootstrap 中移开,并完全依赖它们的样式并使用 React 来更新类。 这对我来说是正确的方法。 现在我意识到像 React Bootstrap 这样的东西存在,但是我已经在我的项目中集成了 vanilla Bootstrap,看起来 React Bootstrap 仍然在版本 4 上,而我正在使用 5。
据我所知,Bootstrap 正在操纵这个 div 上的类: <div id="navbarSupportedContent" style="" class="navbar-collapse collapse">
。 因此,当菜单展开或折叠时,他们似乎正在添加 class collapsing
并删除 class collapse
。 然后,一旦完全显示,类变成navbar-collapse collapse show
和折叠: navbar-collapse collapse
。
Bootstrap 将转换时间设置为 35 秒。 所以这是我的反应代码:
const handleNavCollapse = () => {
if (isNavCollapsed) {
setNavbarClasses('navbar-collapse collapsing');
//setTimeout( <-- I learned this way does not work correctly
setTimeout(() =>
setNavbarClasses('navbar-collapse collapse show'),
350
);
} else {
setNavbarClasses('navbar-collapse collapse');
}
setIsNavCollapsed(!isNavCollapsed);
};
此外,如果这有助于某人找出答案,这里是 CSS,Bootstrap 正在应用collapsing
class:
.collapsing {
height: 0;
overflow: hidden;
transition: height 0.35s ease;
}
它工作一半,因为它在单击汉堡图标时正确显示和隐藏导航栏菜单。 但是没有过渡。 当我像在 Bootstrap 站点上那样在检查器中观看 DOM 时,我没有看到collapsing
的 class 被添加。 我只看到它 add show
和 remove show
。 也许我没有正确执行 setTimeout。
更新:所以我从这个 SO 答案中发现: https://stackoverflow.com/a/42650143/571723实际上我做错了 setTimeout。 我切换到箭头 function。 现在我看到collapsing
的 class 立即添加,然后在 350 毫秒超时后切换到show
。 问题是animation仍然没有过渡,它只是在350ms后显示菜单。
更新 2:我正在进一步调查 Bootstrap 是如何做到这一点的。 当 Bootstrap 在他们的网站上为导航栏设置动画时,我设法截取了控制台的屏幕截图。 所以你可以看到高度设置为一个特定的数字
,并且变化非常快(实际上这个数字没有改变,它被设置为 206px 并保持在那里直到它完全打开)。 您还可以看到height: 0
被覆盖。 这些事情都没有发生在我的站点中的检查员中。
首先让我们从一个小建议开始:不要将类存储为 state。 您真正想要的是存储一些更原始的值,这些值可用于在渲染时派生最终的 UI,包括类。
就像是:
const [isCollapsed, setCollapsed] = React.useState(false); const className = `navbar-collapse ${isCollapsed? '': 'show'}`; return <div className={className}> … </div>;
如果浏览器会在 CSS 属性(例如height
)的auto
和实际单位值(例如12px
)之间进行插值,那么开发可折叠组件将是微不足道的。 但他们没有,你不能从或转换到auto
,但你可以在单位值之间进行插值。
这确实是每个可折叠(或手风琴)UI 小部件在幕后所做的事情,它在已知和明确的单位尺寸之间进行动画处理。 让我们看一下Bootstrap v5.x 的原始可折叠实现(是 Vanilla JS,没有 jQuery) 。
让我们在没有任何噪音的情况下重写这些show()
和hide()
方法,例如添加那些collapsing
类(它们专门用于帮助一些额外的样式)。 (以下是伪代码,绝对与 React 无关!)
class Collapsible extends BaseComponent {
show() {
this.element.style.height = '0px';
this.element.style.transition = 'height 300ms';
this.element.style.height = this.element.scrollHeight + 'px';
}
hide() {
this.element.style.height = this.element.getBoundingClientRect().height + 'px';
this.element.style.transition = 'height 300ms';
this.element.style.height = '0px';
}
}
首先我们分析show()
方法:
this.element.style.height = '0px';
这条线将可折叠元素的height
强制为0px
。
这对于下一个技巧很重要。
this.element.style.transition = 'height 300ms';
只是现在我们设置了过渡配置。 这允许过渡仅在此行之后发生的height
更改时开始。 (实际上这并不容易,这段代码不应该像预期的那样工作,但这或多或少是这个想法)。
this.element.style.height = this.element.scrollHeight + 'px';
我们现在使用HTMLElement.scrollHeight
来检索元素应该具有的高度。 这是有效的,因为scrollHeight
返回可用于滚动的总高度(因此是“滚动”和“高度”),对于具有overflow: hidden
和height: 0px
是内容的总高度。
hide()
方法执行相同的技巧但相反:
this.element.style.height = this.element.getBoundingClientRect().height + 'px';
设置初始高度,但是这次我们使用HTMLElement.getBoundingClientRect()
来获取元素的当前尺寸( width
和height
),因为访问.style.height
会给我们简单的"auto"
,我们需要一个单位值(一个里面有“px”)。
this.element.style.transition = 'height 300ms';
启用过渡。
this.element.style.height = '0px';
通过“隐藏”元素开始过渡。
我们如何在 React 中完成这一切? 简短的回答是“这并不简单”。
您可以纯粹通过 state 转换来实现它,如果您要学习 React,这将是一个很好的练习。
我可以建议的是实际使用一些过渡/动画库来为你做这件事,代价是添加几 KB 的依赖项(尽管彻底评估它)。 您需要检查库是否支持auto
值之间的转换。
一个符合描述的库是react-spring
,它也有一个与您想要实现的或多或少相同的示例: https://codesandbox.io/embed/q3ypxr5yp4
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.