【问题标题】:animate v-if with slide down/up transition (Vue.js 2)使用向下/向上滑动转换动画 v-if (Vue.js 2)
【发布时间】:2020-10-15 20:18:34
【问题描述】:

在我的 Vue 应用程序中,我有一个简单的切换开关,它在活动时呈现一个列表。该列表不应立即出现/消失。我希望在渲染时平滑向下滑动过渡,在隐藏时平滑向上滑动过渡。

以下代码显示了我到目前为止所拥有的,有人知道如何使它工作吗?

new Vue({
  el: '#app',
  data: () => ({
    isOpen: true,
  }),
});
.expand-enter-active,
.expand-leave-active {
  overflow: hidden;
  transition: height .5s linear;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>

<div id="app">
  <button @click="isOpen = !isOpen">
    is open: {{ isOpen }}
  </button>
  <transition name="expand">
    <div v-if="isOpen">
      <div>1</div>
      <div>2</div>
      <div>3</div>
    </div>
  </transition>
</div>

【问题讨论】:

    标签: javascript html css vue.js vuejs2


    【解决方案1】:

    max-height 用于动画,因为我们无法根据此answerheight 属性设置动画

    new Vue({
      el: '#app',
      data: () => ({
        isOpen: false,
      }),
    });
    .expand-enter-active,
    .expand-leave-active {
      transition: max-height .5s ease;
      max-height: 400px;
    }
    
    .expand-enter,
    .expand-leave-to {
      max-height: 0;
      overflow: hidden;
    }
    
    .list {
      box-shadow: 1px 0 10px #aaa;
      padding: 8px;
      width: 64px;
      overflow: hidden;
    }
    <script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
    
    <div id="app">
      <button @click="isOpen = !isOpen">
        Open
      </button>
      <transition name="expand">
        <div v-if="isOpen" class="list">
          <div>1</div>
          <div>2</div>
          <div>3</div>
          <div>4</div>
          <div>5</div>
        </div>
      </transition>
    </div>

    【讨论】:

    • 嘿,谢谢你的回复!抱歉,我还没有使用 Vue3。这是一个 Vue2 应用程序。我在问题中更新了我的代码 sn-p
    • @BoussadjraBrahim 你能再检查一下你的代码吗?我不认为它运作良好。
    • 是的,我不小心从.expand-leave-to中删除了to,请再检查一遍
    • 感谢您的解决方案。不幸的是,css中有一些硬编码的值。我认为这不够动态(在处理生成元素列表的循环时)
    【解决方案2】:

    请看看这个解决方案。

    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,
      }),
    });
    .enter-active,
    .leave-active {
      overflow: hidden;
      transition: height .5s linear;
    }
    <script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
    
    <div id="app">
      <button @click="isOpen = !isOpen">
        is open: {{ isOpen }}
      </button>
      <transition-collapse-height>
        <div v-show="isOpen">
          <div>1</div>
          <div>2</div>
          <div>3</div>
        </div>
      </transition-collapse-height>
    </div>

    【讨论】:

    • 嘿,谢谢你的回复。这不是有点矫枉过正吗? :) 希望能找到一点 CSS 解决方案。我更新了我的问题
    • 如果你定义了transition-collapse-height组件,你可以在其他代码中使用这个。我认为这是一个很好的解决方案。你怎么看。
    • 我选择这个作为答案是因为它是最有活力的一个:)
    【解决方案3】:

    您可以为enter/mount 动画使用关键帧,然后将height 设置为0 而unmount。如果height未知,可以使用max-height代替高度。

    Vue.createApp({
      data() {
        return {
          isOpen: false
        };
      }
    }).mount('#app')
    .expand {
        height: 50px;
        animation: slideDown 1s linear;
        overflow: hidden;
    }
    
    .expand-leave-active.expand-leave-to {
        transition: height 1s ease;
        height: 0;
    }
    
    @keyframes slideDown{
        from {
            height: 0;
        }
        to {
            height: 50px;
        }
    }
    <script src="https://unpkg.com/vue@next"></script>
    
    <div id="app">
      <button @click="isOpen = !isOpen">
        is open: {{ isOpen }}
      </button>
      <transition name="expand">
        <div v-if="isOpen" class="expand">
          <div>1</div>
          <div>2</div>
          <div>3</div>
        </div>
      </transition>
    </div>

    【讨论】:

    • 你的答案很好,但不幸的是,css中有一些硬编码值,如height
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-10-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多