Vuejs过渡css只向下滑动

Ezr*_*ab_ 2 html css css-transitions vue.js vue-transitions

我一直在寻找这个问题的解决方案很长一段时间,但我似乎找不到这个问题的最佳解决方案。基本上我有一个手风琴,当用户打开它时,它应该轻轻地向下滑动,并有一个很好的过渡。

我很确定仅使用 css 就可以做到这一点。如果我错了,请纠正我,但 css 过渡的性能比 js 过渡更好。

现在我面临的问题的 HTML 是:

<transition name="slide-down">
  <ul v-if="isDisplayingOpeningHours" class="mt-2 text-sm flex flex-col space-y-2">
    <li v-for="i in 10" :key="i"> <!-- just for testing purposes -->
      element
    </li>
  </ul>
</transition>
Run Code Online (Sandbox Code Playgroud)

CSS 是:

<transition name="slide-down">
  <ul v-if="isDisplayingOpeningHours" class="mt-2 text-sm flex flex-col space-y-2">
    <li v-for="i in 10" :key="i"> <!-- just for testing purposes -->
      element
    </li>
  </ul>
</transition>
Run Code Online (Sandbox Code Playgroud)

这导致过渡不流畅。滑下来看上去没什么问题,但是滑上去的时候就真的很卡顿,一点也不流畅!如果我设置了max-height: 10rem它并不会使它变得更好。我希望有人可以调试帮助我解决这个问题,也许可以教我更多关于 vue 转换和 js 与 css 转换的知识。

编辑:
只是为了澄清,过渡本身应该仅由 css 组成。手风琴的开场是用js,没问题。另外,如果能看到一个与原生 vue-transition 组件一起使用的转换示例,那就太好了。

编辑2:
这是一个与我有同样问题的codesandbox。 https://codesandbox.io/s/frosty-bash-lmc2f?file=/src/components/HelloWorld.vue

Dip*_*hah 7

另一个更新! 要实现JS过渡可以看官方文档学习。无论如何,我不会实现花哨的计时机制,但以最简单的形式,react 中的 JS 崩溃转换将如下所示,我将其包含在现有的codesandbox中:

<template>
...
  <div>
    <button @click="jsOpen = !jsOpen">Open JS list</button>
    <transition
      v-on:before-enter="beforeEnter"
      v-on:enter="enter"
      v-on:after-enter="afterEnter"
      v-on:enter-cancelled="enterCancelled"
      v-on:before-leave="beforeLeave"
      v-on:leave="leave"
      v-on:after-leave="afterLeave"
      v-on:level-cancelled="leaveCancelled"
      v-bind:css="false"
    >
      <ul v-if="jsOpen" class="mt-2 text-sm flex flex-col space-y-2">
        <li v-for="i in 10" :key="i">item-{{ i }}</li>
      </ul>
    </transition>
  </div>
</template>

<script>
export default {
  ...
  methods: {
    beforeEnter(el) {
      el.style.height = 0;
      el.style.overflow = "hidden";
    },
    enter(el, done) {
      const increaseHeight = () => {
        if (el.clientHeight < el.scrollHeight) {
          const height = `${parseInt(el.style.height) + 5}px`;
          el.style.height = height;
        } else {
          clearInterval(this.enterInterval);
          done();
        }
      };
      this.enterInterval = setInterval(increaseHeight, 10);
    },
    afterEnter(el) {},
    enterCancelled(el) {
      clearInterval(this.enterInterval);
    },
    beforeLeave(el) {},
    leave(el, done) {
      const decreaseHeight = () => {
        if (el.clientHeight > 0) {
          const height = `${parseInt(el.style.height) - 5}px`;
          el.style.height = height;
        } else {
          clearInterval(this.leaveInterval);
          done();
        }
      };
      this.leaveInterval = setInterval(decreaseHeight, 10);
    },
    afterLeave(el) {},
    leaveCancelled(el) {
      clearInterval(this.leaveInterval);
    },
  },
};
</script>
Run Code Online (Sandbox Code Playgroud)

更新: 在了解OP的要求后,我试图尝试不同的东西,我偶然发现了这篇关于css-tricks的文章,其中详细解释了有关转换的更多细节,从该文章中提出的另一个非js解决方案如下所示,我将其包含在现有的stackblitz中:

.scale-enter-active,
.scale-leave-active {
  transform-origin: top;
  transition: transform 0.3s ease-in-out;
}

.scale-enter-to,
.scale-leave-from {
  transform: scaleY(1);
}

.scale-enter-from,
.scale-leave-to {
  transform: scaleY(0);
}
Run Code Online (Sandbox Code Playgroud)

这里不是高度,而是相对 y 轴缩放。IT 还有一个副作用,即它首先将容器扩展到完整大小,然后更新(缩放)内容。

Vue v3.x -leaveV3-enter中的类被重命名为和。看看这个stackblitz-leave-from-enter-from

.slidedown-enter-active,
.slidedown-leave-active {
  transition: max-height 0.5s ease-in-out;
}

.slidedown-enter-to,
.slidedown-leave-from {
  overflow: hidden;
  max-height: 1000px;
}

.slidedown-enter-from,
.slidedown-leave-to {
  overflow: hidden;
  max-height: 0;
}
Run Code Online (Sandbox Code Playgroud)

Vue v2.x 问题是您指定max-height为 100%,使用一些大于您预期最大高度的值。将您的样式更新为:

.slide-down-enter-active,
.slide-down-leave-active {
  transition: max-height 0.5s ease-in-out;
}

.slide-down-enter-to,
.slide-down-leave {
  overflow: hidden;
  max-height: 1000px;
}

.slide-down-enter,
.slide-down-leave-to {
  overflow: hidden;
  max-height: 0;
}
Run Code Online (Sandbox Code Playgroud)

它应该有效。看看这个codesandbox演示。