vuejs如何实现这样的展开收起动画?

图片描述

如图中的是jquery实现的,那么在vue中如何实现呢?
我试着用<transition>,但是用的很笨,望前辈们指教指教,如果能贴个示例代码的话,万分感谢~!

阅读 18.6k
评论 2017-09-26 提问
    7 个回答
    斯年
    • 649

    这个组件当初自己也搞了很久,最后因为不知道隐藏层的高度没有使用css实现效果,可以参考element-ui通过overflow获取高度的方法创建了一个函数式组件实现了效果:

    const elTransition = '0.3s height ease-in-out, 0.3s padding-top ease-in-out, 0.3s padding-bottom ease-in-out'
    const Transition = {
      'before-enter' (el) {
        el.style.transition = elTransition
        if (!el.dataset) el.dataset = {}
    
        el.dataset.oldPaddingTop = el.style.paddingTop
        el.dataset.oldPaddingBottom = el.style.paddingBottom
    
        el.style.height = 0
        el.style.paddingTop = 0
        el.style.paddingBottom = 0
      },
    
      'enter' (el) {
        el.dataset.oldOverflow = el.style.overflow
        if (el.scrollHeight !== 0) {
          el.style.height = el.scrollHeight + 'px'
          el.style.paddingTop = el.dataset.oldPaddingTop
          el.style.paddingBottom = el.dataset.oldPaddingBottom
        } else {
          el.style.height = ''
          el.style.paddingTop = el.dataset.oldPaddingTop
          el.style.paddingBottom = el.dataset.oldPaddingBottom
        }
    
        el.style.overflow = 'hidden'
      },
    
      'after-enter' (el) {
        el.style.transition = ''
        el.style.height = ''
        el.style.overflow = el.dataset.oldOverflow
      },
    
      'before-leave' (el) {
        if (!el.dataset) el.dataset = {}
        el.dataset.oldPaddingTop = el.style.paddingTop
        el.dataset.oldPaddingBottom = el.style.paddingBottom
        el.dataset.oldOverflow = el.style.overflow
    
        el.style.height = el.scrollHeight + 'px'
        el.style.overflow = 'hidden'
      },
    
      'leave' (el) {
        if (el.scrollHeight !== 0) {
          el.style.transition = elTransition
          el.style.height = 0
          el.style.paddingTop = 0
          el.style.paddingBottom = 0
        }
      },
    
      'after-leave' (el) {
        el.style.transition = ''
        el.style.height = ''
        el.style.overflow = el.dataset.oldOverflow
        el.style.paddingTop = el.dataset.oldPaddingTop
        el.style.paddingBottom = el.dataset.oldPaddingBottom
      }
    }
    
    export default {
      name: 'collapseTransition',
      functional: true,
      render (h, { children }) {
        const data = {
          on: Transition
        }
        return h('transition', data, children)
      }
    }
    

    然后就可以在需要的地方当做组件使用(不再需要css与其它逻辑):

      <!-- 隐藏部分
      -------------------------- --> 
      <collapse-transition>
         <div class="collapse-wrap"
           v-show="isActive">
          <!-- @slot default -->
          <slot></slot>
        </div> 
      </collapse-transition>
    评论 赞赏 2017-09-26

      给你个demo吧

      <!DOCTYPE html>
      <html lang="en">
      <head>
          <meta charset="UTF-8">
          <title>Title</title>
          <style>
              .box{
                  height:500px;
                  background-color:black;  
                   overflow: hidden;                       
              }
              .mybox-leave-active,.mybox-enter-active{
                  transition:  all 1s ease; 
              }
              .mybox-leave-active,.mybox-enter{
                  height:0px !important;
              }
              .mybox-leave,.mybox-enter-active{
                  height: 500px;
              }
          </style>
      </head>
      <body>
      <div id="box">
          <transition name="mybox">
              <div class="box"  v-show="boxshow"></div>
          </transition>
          <button @click="togglebox">按钮</button>
      </div>
      </body>
      <script src="../bower_components/vue/dist/vue.js"></script>
      <script>
          new Vue({
              el:'#box',
              data:{
                  boxshow:false
              },
              methods:{
                 
                  togglebox:function(){
                      this.boxshow = !this.boxshow;
                  }
              }      
          });
      </script>
      </html>
      评论 赞赏 2017-09-26

        用动画试试看:

        <transition name="router-slid">
           //需要动画的内容
        </transition>
        

        css:

        .router-slid-enter-active, .router-slid-leave-active {
          transition: all .4s;
        }
        .router-slid-enter, .router-slid-leave-active {
          transform: translate3d(0, 3rem, 0);
          opacity: 0;
        }
        评论 赞赏 2017-09-26

          可以参考这个,基本就是这样,你稍微调下样式就可以了

          <template>
              <div class="panel">
                  <!-- body -->
                  <transition name="panel-fade" 
                      @enter="enter"
                      @before-leave="beforeLeave"
                      @leave="leave"
                  >
                      <div class="panel__body" v-show="ifShowBody">
                          <slot></slot>
                      </div>
                  </transition>
                  <!-- footer -->
                  <div class="panel__footer" >
                      <slot name="header">更多</slot>
                      <i v-if="showIcon" class="panel__header__icon" :class="{[`arrow--${iconClass}`]: true}" @click="iconClick"></i>
                  </div>
          
              </div>
          </template>
          <script>
          import velocity from 'velocity-animate'
          
          export default {
              name: "ezy-panel",
              props: {
                  showIcon: {
                      type: Boolean,
                      default: true
                  }
              },
              data() {
                  return {
                      iconClass: 'up',
                      bodyHeight: 0
                  }
              },
              computed: {
                  ifShowBody() {
                      var c = true;
                      switch (this.iconClass) {
                          case 'up':
                              c = true
                              break;
                          case 'down':
                              c = false
                              break;
                      }
                      return c
                  }
              },
              methods: {
                  iconClick() {
                      var self = this;
                      switch (this.iconClass) {
                          case 'up':
                              this.iconClass = 'down';
          
                              break;
                          case 'down':
                              this.iconClass = 'up';
          
                              break;
                      }
                  },
                  enter(el, done){
                      var self = this;
                      velocity(el, { height: self.bodyHeight + 'px' }, { duration: 500 , complete: done})
                  },
                  beforeLeave(el,done){
                      this.bodyHeight = el.clientHeight;
                  },
                  leave(el, done) {
                      el.style.height = el.clientHeight + 'px';
                      velocity(el, { height: '0px' }, { duration: 500 , complete: done})
                  }
              }
          }

          用的时候,直接写主体部分可以,尾部的展开收缩,在组件里有了。

          <panel>
          /* 直接写主体部分
           *  <div>...</div>
           */
          </panel>
          评论 赞赏 2017-09-26

            vue transition很容易的说。 用max-height效果最佳

                in .vue:
                <transition name="sub-comments">
                <div>...</div>
                </transition>
                
                
                in css:
               .sub-comments-leave-active,.sub-comments-enter-active {
                    transition: max-height 0.3s;
                }
                .sub-comments-enter,.sub-comments-leave-to {
                    max-height:0 ;
                }
                .sub-comments-enter-to,.sub-comments-leave {
                    max-height: 4rem ;
                }
            评论 赞赏 2019-07-15

              变量控制状态:

              外部控制height,overflow:hidden
              内部控制一个transform:translateY

              评论 赞赏 2017-09-26
                不明所以
                • 2
                • 新人请关照

                上面的都能实现 ,其实大致思路都一样.附上另一种写法

                vue部分
                <divclass="moreInfo" @click="boxshow = !boxshow">
                        展开
                </div>
                <div :class="boxshow==true?'box':'boxHidden' " ></div>
                //boxshow默认为false
                css部分
                .box {
                        height:200px;
                        width: 100%;
                        background-color:black;
                        transition: all 0.5s ease-in-out;
                    }
                    .boxHidden{
                        transition: all 1s ease-in-out;
                        height: 0;
                        overflow: hidden;
                    }
                评论 赞赏 2019-09-17
                  撰写回答

                  登录后参与交流、获取后续更新提醒