v-if上平滑的vue崩溃过渡

时间:2018-08-25 19:31:56

标签: javascript css vuejs2 transitions

我正在努力尝试使用v-if平滑显示/隐藏内容的vue过渡。虽然我了解css的类和过渡,但是我可以使用不透明度或翻译等方法使内容“平滑”显示...但是一旦动画完成(或开始播放),下面的任何html部分似乎都会“跳转” '。

我正在尝试实现与Bootstrap 4'collapse'类相同的效果-单击此处的顶部按钮之一:https://getbootstrap.com/docs/4.0/components/collapse/

随着隐藏部分的出现/消失,所有html内容都会随之滑动。

对于使用v-if显示的内容,是否可以使用Vue转换?转换开始或完成后,vue转换文档上的所有示例均具有出色的css转换效果,但都具有以下html“跳转”。

我已经看到一些使用max-height的纯js解决方案-https://jsfiddle.net/wideboy32/7ap15qq0/134/

并尝试使用vue:https://jsfiddle.net/wideboy32/eywraw8t/303737/

.smooth-enter-active, .smooth-leave-active {
  transition: max-height .5s;
}
.smooth-enter, .smooth-leave-to {
  max-height: 0 .5s;
}

谢谢!

2 个答案:

答案 0 :(得分:3)

如果要设置max-height的动画,则应输入要设置动画的元素的max-height的数量,并在将max定义中放入“ s”(或秒)时更正第二类。 :

p{
  max-height: 20px;
}
.smooth-enter-active, .smooth-leave-active {
  transition: max-height .5s;
}
.smooth-enter, .smooth-leave-to {
  max-height: 0;
}

如果您希望bs4崩溃,则vue网站中的示例将:

.smooth-enter-active, .smooth-leave-active {
  transition: opacity .5s;
}
.smooth-enter, .smooth-leave-to {
  opacity: 0
}

编辑: 通过首先找出内容的高度,然后将其设置在.*-enter-to.*-leave类中,可以实现您想做的事情。下面的小提琴演示了一种实现此目的的方法:

https://jsfiddle.net/rezaxdi/sxgyj1f4/3/

您也可以完全忘记v-if或v-show,而只需使用高度值隐藏元素即可,我认为这很平滑:

https://jsfiddle.net/rezaxdi/tgfabw65/9/

答案 1 :(得分:2)

我也有类似的任务。 我发现没有JS是不可能做到的。 因此,我编写了自定义过渡组件(Reusable Transitions),它对我有用:

Vue.component('transition-collapse-height', {
  template: `<transition
    enter-active-class="enter-active"
    leave-active-class="leave-active"
    @before-enter="beforeEnter"
    @enter="enter"
    @after-enter="afterEnter"
    @before-leave="beforeLeave"
    @leave="leave"
    @after-leave="afterLeave"
  >
    <slot />
  </transition>`,
  methods: {
    /**
     * @param {HTMLElement} element
     */
    beforeEnter(element) {
      requestAnimationFrame(() => {
        if (!element.style.height) {
          element.style.height = '0px';
        }

        element.style.display = null;
      });
    },
    /**
     * @param {HTMLElement} element
     */
    enter(element) {
      requestAnimationFrame(() => {
        requestAnimationFrame(() => {
          element.style.height = `${element.scrollHeight}px`;
        });
      });
    },
    /**
     * @param {HTMLElement} element
     */
    afterEnter(element) {
      element.style.height = null;
    },
    /**
     * @param {HTMLElement} element
     */
    beforeLeave(element) {
      requestAnimationFrame(() => {
        if (!element.style.height) {
          element.style.height = `${element.offsetHeight}px`;
        }
      });
    },
    /**
     * @param {HTMLElement} element
     */
    leave(element) {
      requestAnimationFrame(() => {
        requestAnimationFrame(() => {
          element.style.height = '0px';
        });
      });
    },
    /**
     * @param {HTMLElement} element
     */
    afterLeave(element) {
      element.style.height = null;
    },
  },
});

new Vue({
  el: '#app',
  data: () => ({
    isOpen: true,
  }),
  methods: {
    onClick() {
      this.isOpen = !this.isOpen;
    }
  }
});
.enter-active,
.leave-active {
  overflow: hidden;
  transition: height 1s linear;
}

.content {
  background: grey;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">
  <button @click="onClick">
    open/hide
  </button>
  <transition-collapse-height>
   <div v-show="isOpen" class="content">
     <br/>
     <br/>
     <br/>
     <br/>
   </div>
  </transition-collapse-height>
</div>