如何用原生JavaScript实现带动画的元素显示隐藏效果
原生JS实现无CSS依赖的
show('slow')/hide('slow')等价效果 直接修改display属性会触发瞬时切换,核心原因是display属于离散CSS属性,不存在可插值的中间状态,浏览器会直接渲染最终样式。jQuery的show('slow')/hide('slow')本身也不是靠CSS过渡实现,而是通过JS逐帧修改元素尺寸、边距类属性完成动画,你完全可以用原生API复刻完全一致的效果,不需要引入任何额外CSS规则。
jQuery中slow参数对应动画时长为400ms,默认使用swing缓动曲线,以下是完全等价的原生实现,默认仅做尺寸类属性动画,不包含透明度、位移变化,就是你需要的组装式展开/收起效果:
/** * 等价jQuery show/hide动画 无CSS依赖 * @param {HTMLElement} el 目标元素 * @param {number} duration 动画时长 slow对应400ms * @param {'show'|'hide'} type 动画类型 */ function toggleFormAnimate(el, duration = 400, type) { if (el.dataset.animating === 'true') return; el.dataset.animating = 'true'; const sizeProps = [ 'height', 'paddingTop', 'paddingBottom', 'marginTop', 'marginBottom', 'borderTopWidth', 'borderBottomWidth' ]; const getStyleVal = (target, prop) => parseFloat(window.getComputedStyle(target)[prop]) || 0; let startVals = {}, endVals = {}; if (type === 'hide') { const curDisplay = window.getComputedStyle(el).display; el.style.display = curDisplay === 'none' ? 'block' : curDisplay; sizeProps.forEach(prop => { startVals[prop] = getStyleVal(el, prop); endVals[prop] = 0; }); } else { // 临时显示元素获取原始目标尺寸 el.style.visibility = 'hidden'; const originDisplay = window.getComputedStyle(el).display; el.style.display = originDisplay === 'none' ? 'block' : originDisplay; sizeProps.forEach(prop => { endVals[prop] = getStyleVal(el, prop); startVals[prop] = 0; }); el.style.visibility = ''; sizeProps.forEach(prop => el.style[prop] = '0px'); } el.style.overflow = 'hidden'; // jQuery默认swing缓动 const swingEase = (t) => 0.5 - Math.cos(t * Math.PI) / 2; const startTs = performance.now(); function runFrame(now) { const progress = Math.min((now - startTs) / duration, 1); const easedProgress = swingEase(progress); sizeProps.forEach(prop => { const val = startVals[prop] + (endVals[prop] - startVals[prop]) * easedProgress; el.style[prop] = `${val}px`; }); if (progress < 1) { requestAnimationFrame(runFrame); } else { // 动画结束 清理临时行内样式 不破坏原有布局 el.dataset.animating = 'false'; el.style.overflow = ''; sizeProps.forEach(prop => el.style[prop] = ''); el.style.display = type === 'hide' ? 'none' : ''; } } requestAnimationFrame(runFrame); } // 替换原有jQuery代码即可 toggleFormAnimate(document.querySelector('#form-1'), 400, 'hide'); toggleFormAnimate(document.querySelector('#form-2'), 400, 'show');
实现说明
- 全程通过JS动态写入行内样式完成动画,不需要提前写任何CSS类、transition或animation规则,动画结束后会自动清理所有临时添加的行内样式,不会影响元素原有响应式布局逻辑
- 内置动画锁,避免短时间重复触发动画导致的样式错乱
- 动画过程中自动添加
overflow: hidden避免内容溢出,动画结束自动移除 - 缓动曲线、动画时长和jQuery默认的
slow参数完全对齐,视觉效果和原有实现无差异 - 如果后续需要调整动画属性,只需要修改
sizeProps数组即可,比如不需要边框动画就删掉数组里的border相关属性
内容的提问来源于stack exchange,提问作者JSDevGuy
相关产品推荐
相关产品推荐

