Плавный переход на V-If - PullRequest
       21

Плавный переход на V-If

0 голосов
/ 25 августа 2018

Я борюсь с переходами vue, пытаясь плавно показать / скрыть контент, используя v-if. Хотя я понимаю классы и переходы css, я могу сделать так, чтобы содержимое выглядело «плавно», используя такие вещи, как непрозрачность, перевод и т. Д., Но как только анимация завершена (или, скорее, как она начинается), любые HTML-разделы ниже кажутся «перепрыгивающими» .

Я пытаюсь добиться того же эффекта, что и у класса Bootstrap 4 «развал» - нажмите одну из верхних кнопок здесь: https://getbootstrap.com/docs/4.0/components/collapse/

Когда скрытый раздел появляется / исчезает, все html-содержимое красиво «скользит» вместе с ним.

Возможно ли это с помощью перехода Vue для отображения контента с использованием v-if? Все сэмплы в документах vue Переходы, хотя и имеют большие эффекты CSS-перехода, имеют приведенный ниже HTML-переход, как только переход начался или завершен.

Я видел несколько чистых js-решений, использующих max-height - 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 голосов
/ 13 марта 2019

У меня тоже была похожая задача.Я обнаружил, что это невозможно без JS.Поэтому я пишу пользовательский компонент перехода ( Многоразовые переходы ), и он работает для меня:

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>
0 голосов
/ 25 августа 2018

Если вы хотите анимировать max-height, вам нужно ввести значение max-height для элемента, который вы хотите анимировать, а также исправить второй класс, указав 's' (или секунды) в определении max-height :

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/

...