7

所以我有这个很棒的小代码块,我试图在没有 jQuery 的情况下将其重写为纯 JavaScript 和 CSS。

jQuery.extend(jQuery.easing,{
    easeInExpo: function (x, t, b, c, d) {
        return (t==0) ? b : c * Math.pow(2, 10 * (t/d - 1)) + b;
    }
}); 

var nset = false;
$('button#hmenu').click(function(){
    if(!nset){
        $('ul#nav').delay(35).slideDown(300,'easeInExpo');
        $('button#hmenu').addClass('active');
        nset = true;
    } else {
        $('ul#nav').slideUp(550);
        nset = false;
        $('button#hmenu').removeClass('active');
    }
})  

我正在查看一些使用缓动的 CSS 过渡,但只是想知道选项是什么?在我的代码中,我有一个 slideDown 和 up 缓动函数。这在生产中用于移动菜单导航。

4

2 回答 2

9

更新:

这个 github repo(你不需要 jQuery)有一个非常全面的常用 jQuery 函数列表,全部用 vanilla Javascript 重写。

它包括动画、查询选择器、ajax、事件和其他高级 jQuery 功能。

稍旧的youmightnotneedjquery.com也非常好,特别是如果您需要支持较旧的 IE 版本。

您可以使用本网站easeInExpo提供的以下 CSS来实现样式动画:

transition: all 500ms cubic-bezier(0.950, 0.050, 0.795, 0.035);

下面的示例说明height了 div 的缓动属性。我已对其进行了更新,以匹配您在单击时在 jQuery 中添加的延迟(35 毫秒)、时间(分别为 300 毫秒和 550 毫秒)以及 jQuery 的默认缓动('swing')——正如这个答案所提供的——当它关闭时:

let expandable = document.getElementById('expandable');
let expandButton = document.getElementById('expand-button');

expandButton.addEventListener('click', () => {
  expandable.classList.toggle('expanded');
});
#expandable {
  background: red;
  transition: all 550ms cubic-bezier(.02, .01, .47, 1);
  height: 0px;
  width: 100px;
  transition-delay: 0ms;
}

#expandable.expanded {
  height: 100px;
  transition-delay: 35ms;
  transition: all 300ms cubic-bezier(0.950, 0.050, 0.795, 0.035);
}
<div id="expandable"></div>
<br />
<button id="expand-button">Toggle expand</button>

于 2021-10-01T04:21:57.293 回答
3

为了让您的可折叠组件扩展到可变高度,这里需要一点魔法。如果您只是每次都扩展到相同的高度,比如 100 像素,那么这很简单,就像创建一个单一的类(如“expanded”),然后将该类作为布尔开关添加和删除。

我们仍将使用布尔开关用于可变高度,但我们还需要使用 JavaScript 获取每个可扩展元素的高度,然后如果用户窗口的大小发生变化以考虑文本换行,则刷新这些高度值,图像调整大小等。

我们可以很简单地使用自定义 CSS 属性(变量),使用回退值 to unset,这意味着当可变高度存在时,作为最后的手段,框将展开以显示所有内容而不使用动画,但在大多数情况下,如果不是全部的话情况(以及所有现代浏览器)自定义 CSS 变量应该是每个部分唯一值的理想解决方案。

在这里它正在运行(如下),带有切换和手风琴示例,以及用于与您在原始问题中提供的 easeInExpo 函数紧密匹配的三次贝塞尔缓动函数。cubic-bezier(0.95, 0.05, 0.795, 0.035)我从easings.net/en#easeInExpo中提取了这个缓动函数,他们有一个用于 easeInExpo 和许多其他的纯 CSS 缓动。

简单示例

const expandables = document.querySelectorAll('.expandable');
const setInnerHeights = () => {
  for (const expandable of expandables) {
    expandable.style.setProperty('--inner-height', Array.from(expandable.children).map(child => child.offsetHeight).reduce((a, c) => a + c, 0) + 'px');
  }
};
setInnerHeights();
document.addEventListener('click', e => {
  if (e.target?.matches('.expand-trigger')) {
    const expandable = e.target.nextElementSibling;
    expandable.classList[expandable.classList.contains('expanded') ? 'remove' : 'add']('expanded');
  }
});
window.addEventListener('resize', setInnerHeights);
html {
  height: 100%;
  box-sizing: border-box;
}
*, *::before, *::after {
  box-sizing: inherit;
}
body {
  display: flex;
  flex-direction: column;
  align-items: stretch;
  justify-content: flex-start;
  min-height: 100%;
  padding: 20px;
}
.expandable {
  max-height: 0;
  overflow: hidden;
  transition: max-height 0.25s cubic-bezier(0.95, 0.05, 0.795, 0.035);
  text-align: left;
}
.expandable > p {
  margin: 0;
  padding: 10px 0;
}
.expandable.expanded {
  --content-height: calc(var(--inner-height) + 20px);
  max-height: var(--content-height, unset);
}
<button class="expand-trigger">Expand #1</button>
<div class="expandable">
  <p>Lorem ipsum dolor sit amet.</p>
</div>
<button class="expand-trigger">Expand #2</button>
<div class="expandable">
  <p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nam mi purus, interdum id mattis et, posuere nec urna. Mauris in ornare sem. Phasellus non eros augue. Fusce tempus bibendum mauris, vel luctus est viverra eget. Cras vitae lectus magna. Integer vulputate est ut felis dictum consectetur. Nunc vitae enim at sem rhoncus aliquet et id risus. Etiam faucibus quis turpis eu pellentesque. Aliquam dictum lorem nec orci finibus commodo. Etiam tincidunt lacinia consectetur. Praesent tortor lorem, imperdiet sed varius vel, varius ac quam. Vestibulum aliquam lorem sem, sit amet imperdiet purus commodo eu. Integer a iaculis tortor.</p>
</div>
<button class="expand-trigger">Expand #3</button>
<div class="expandable">
  <p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nam mi purus, interdum id mattis et, posuere nec urna. Mauris in ornare sem. Phasellus non eros augue. Fusce tempus bibendum mauris, vel luctus est viverra eget. Cras vitae lectus magna. Integer vulputate est ut felis dictum consectetur. Nunc vitae enim at sem rhoncus aliquet et id risus. Etiam faucibus quis turpis eu pellentesque. Aliquam dictum lorem nec orci finibus commodo. Etiam tincidunt lacinia consectetur. Praesent tortor lorem, imperdiet sed varius vel, varius ac quam. Vestibulum aliquam lorem sem, sit amet imperdiet purus commodo eu. Integer a iaculis tortor.</p>
  <p>Integer convallis lectus eu felis bibendum, vel lacinia metus imperdiet. Maecenas vulputate, quam vitae tempus pretium, erat felis euismod risus, nec blandit leo mi eget purus. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Integer at neque laoreet, egestas dui ut, bibendum lorem. Maecenas elementum odio a congue facilisis. Vivamus risus urna, vestibulum egestas sem nec, lacinia volutpat metus. Suspendisse potenti. Suspendisse ullamcorper commodo libero, sed rhoncus nibh porta in. Donec mi felis, posuere luctus varius ac, faucibus vitae erat.</p>
</div>

复杂示例

const initAccordions = () => {
  const getNode = selector => document.querySelector(selector),
      getNodes = selector => Array.from(document.querySelectorAll(selector)),
      findChildren = (node, selector) => Array.from(node.children).filter(e => e.matches?.(selector)),
      findChild = (node, selector) => Array.from(node.children).find(e => e.matches?.(selector)),
      _addInput = (node, position, id, checked) => node.insertAdjacentHTML(position, `<input type="radio" name="accordion-${id}"${checked ? ' checked="checked"' : ''}>`),
      setInnerHeight = node => {
        const height = Array.from(node.children).map(child => child.offsetHeight).reduce((a, c) => a + c, 0) + 'px';
        node.style.setProperty('--inner-height', height);
      },
      accordions = Array.from(document.querySelectorAll('.accordion'));
  let accordionIndex = 0;
  for (const accordion of accordions) {
    const isToggle = accordion.dataset?.type === 'toggle',
        panels = findChildren(accordion, '.accordion--panel');
    let panelIndex = 0;
    for (const panel of panels) {
      const title = findChild(panel, '.accordion--panel--title'),
          content = findChild(panel, '.accordion--panel--content'),
          addInput = (node, position, checked) => _addInput(node, position, accordionIndex + (isToggle ? '-' + panelIndex : ''), checked);
      setInnerHeight(content);
      addInput(title, 'beforebegin');
      addInput(title, 'afterbegin', true);
      panelIndex++;
    }
    accordionIndex++;
  }
  window.addEventListener('resize', () => {
    const panelContents = Array.from(document.querySelectorAll('.accordion > .accordion--panel > .accordion--panel--content'));
    for (const content of panelContents) setInnerHeight(content);
  });
};
initAccordions();
html {
  height: 100%;
  box-sizing: border-box;
}
*, *::before, *::after {
  box-sizing: inherit;
}
body {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: flex-start;
  min-height: 100%;
  padding: 20px;
}
.accordion--panel > [type=checkbox],
.accordion--panel > [type=radio], .accordion--panel--title > [type=checkbox],
.accordion--panel--title > [type=radio] {
  -webkit-appearance: none;
     -moz-appearance: none;
          appearance: none;
  display: block;
  position: absolute;
  left: 0;
  top: 0;
  width: 100%;
  height: 100%;
  cursor: pointer;
}
.accordion--panel > [type=checkbox]:checked,
.accordion--panel > [type=radio]:checked, .accordion--panel--title > [type=checkbox]:checked,
.accordion--panel--title > [type=radio]:checked {
  display: none;
}
.accordion--panel {
  border-radius: 7px;
}
.accordion--panel--title {
  background-color: #ccc;
}
.accordion--panel--content {
  box-shadow: inset 0 0 0 2px #ccc;
  border-radius: 0 0 7px 7px;
}
.accordion {
  display: flex;
  flex-direction: column;
  gap: 10px;
  width: 100%;
  max-width: 500px;
}
.accordion--panel {
  display: flex;
  flex-direction: column;
  position: relative;
  overflow: hidden;
}
.accordion--panel > [type=checkbox],
.accordion--panel > [type=radio] {
  z-index: 1;
}
.accordion--panel--title, .accordion--panel--content {
  padding-inline: 15px;
}
.accordion--panel--title {
  position: relative;
  padding-block: 10px;
}
.accordion--panel--content {
  max-height: 0;
  overflow: hidden;
  transition: max-height 0.25s cubic-bezier(0.95, 0.05, 0.795, 0.035);
}
.accordion--panel--content--inner > p:first-child {
  margin-top: 10px;
}
.accordion--panel--content--inner > p:last-child {
  margin-bottom: 10px;
}
[type=checkbox]:checked ~ .accordion--panel--content, [type=radio]:checked ~ .accordion--panel--content {
  --content-height: calc(var(--inner-height) + 20px);
  max-height: var(--content-height, unset);
}
<h2>Accordion Demo</h2>
<div class="accordion" data-type="accordion">
  <div class="accordion--panel">
    <div class="accordion--panel--title">Title #1</div>
    <div class="accordion--panel--content">
      <div class="accordion--panel--content--inner">
        <p>Lorem ipsum dolor sit amet.</p>
      </div>
    </div>
  </div>
  <div class="accordion--panel">
    <div class="accordion--panel--title">Title #2</div>
    <div class="accordion--panel--content">
      <div class="accordion--panel--content--inner">
        <p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nam mi purus, interdum id mattis et, posuere nec urna. Mauris in ornare sem. Phasellus non eros augue. Fusce tempus bibendum mauris, vel luctus est viverra eget. Cras vitae lectus magna. Integer vulputate est ut felis dictum consectetur. Nunc vitae enim at sem rhoncus aliquet et id risus. Etiam faucibus quis turpis eu pellentesque. Aliquam dictum lorem nec orci finibus commodo. Etiam tincidunt lacinia consectetur. Praesent tortor lorem, imperdiet sed varius vel, varius ac quam. Vestibulum aliquam lorem sem, sit amet imperdiet purus commodo eu. Integer a iaculis tortor.</p>
      </div>
    </div>
  </div>
  <div class="accordion--panel">
    <div class="accordion--panel--title">Title #3</div>
    <div class="accordion--panel--content">
      <div class="accordion--panel--content--inner">
        <p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nam mi purus, interdum id mattis et, posuere nec urna. Mauris in ornare sem. Phasellus non eros augue. Fusce tempus bibendum mauris, vel luctus est viverra eget. Cras vitae lectus magna. Integer vulputate est ut felis dictum consectetur. Nunc vitae enim at sem rhoncus aliquet et id risus. Etiam faucibus quis turpis eu pellentesque. Aliquam dictum lorem nec orci finibus commodo. Etiam tincidunt lacinia consectetur. Praesent tortor lorem, imperdiet sed varius vel, varius ac quam. Vestibulum aliquam lorem sem, sit amet imperdiet purus commodo eu. Integer a iaculis tortor.</p>
        <p>Integer convallis lectus eu felis bibendum, vel lacinia metus imperdiet. Maecenas vulputate, quam vitae tempus pretium, erat felis euismod risus, nec blandit leo mi eget purus. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Integer at neque laoreet, egestas dui ut, bibendum lorem. Maecenas elementum odio a congue facilisis. Vivamus risus urna, vestibulum egestas sem nec, lacinia volutpat metus. Suspendisse potenti. Suspendisse ullamcorper commodo libero, sed rhoncus nibh porta in. Donec mi felis, posuere luctus varius ac, faucibus vitae erat.</p>
      </div>
    </div>
  </div>
</div>
<h2>Toggle Demo</h2>
<div class="accordion" data-type="toggle">
  <div class="accordion--panel">
    <div class="accordion--panel--title">Title #1</div>
    <div class="accordion--panel--content">
      <div class="accordion--panel--content--inner">
        <p>Lorem ipsum dolor sit amet.</p>
      </div>
    </div>
  </div>
  <div class="accordion--panel">
    <div class="accordion--panel--title">Title #2</div>
    <div class="accordion--panel--content">
      <div class="accordion--panel--content--inner">
        <p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nam mi purus, interdum id mattis et, posuere nec urna. Mauris in ornare sem. Phasellus non eros augue. Fusce tempus bibendum mauris, vel luctus est viverra eget. Cras vitae lectus magna. Integer vulputate est ut felis dictum consectetur. Nunc vitae enim at sem rhoncus aliquet et id risus. Etiam faucibus quis turpis eu pellentesque. Aliquam dictum lorem nec orci finibus commodo. Etiam tincidunt lacinia consectetur. Praesent tortor lorem, imperdiet sed varius vel, varius ac quam. Vestibulum aliquam lorem sem, sit amet imperdiet purus commodo eu. Integer a iaculis tortor.</p>
      </div>
    </div>
  </div>
  <div class="accordion--panel">
    <div class="accordion--panel--title">Title #3</div>
    <div class="accordion--panel--content">
      <div class="accordion--panel--content--inner">
        <p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nam mi purus, interdum id mattis et, posuere nec urna. Mauris in ornare sem. Phasellus non eros augue. Fusce tempus bibendum mauris, vel luctus est viverra eget. Cras vitae lectus magna. Integer vulputate est ut felis dictum consectetur. Nunc vitae enim at sem rhoncus aliquet et id risus. Etiam faucibus quis turpis eu pellentesque. Aliquam dictum lorem nec orci finibus commodo. Etiam tincidunt lacinia consectetur. Praesent tortor lorem, imperdiet sed varius vel, varius ac quam. Vestibulum aliquam lorem sem, sit amet imperdiet purus commodo eu. Integer a iaculis tortor.</p>
        <p>Integer convallis lectus eu felis bibendum, vel lacinia metus imperdiet. Maecenas vulputate, quam vitae tempus pretium, erat felis euismod risus, nec blandit leo mi eget purus. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Integer at neque laoreet, egestas dui ut, bibendum lorem. Maecenas elementum odio a congue facilisis. Vivamus risus urna, vestibulum egestas sem nec, lacinia volutpat metus. Suspendisse potenti. Suspendisse ullamcorper commodo libero, sed rhoncus nibh porta in. Donec mi felis, posuere luctus varius ac, faucibus vitae erat.</p>
      </div>
    </div>
  </div>
</div>

easings.net提供了其他 CSS 缓动函数。

您还可以使用 Chrome 的 DevTools 通过将transitiontransition-timing-function属性添加到值为 的任何元素ease,然后单击单词旁边的方形曲线图标ease并拖动任一圆形手柄,可以直观地自定义您的缓动功能。

于 2021-10-04T19:36:49.170 回答