Vue中实现菜单下拉、收起的动画效果

菜单的下拉和收起动画,看起来好像比较简单,但是搞了半天。

最后可以使用的代码:

        <transition
          name="default"
          v-on:enter="menuEnter"
          v-on:leave="menuLeave"
          enter-class="default-enter"
          leave-to-class="default-leave-to"
        >
          <ul v-if="hasChildren(node, index)" class="menu-l2">
            <li
              v-for="(subnode, subIndex) in node.children"
              :key="subnode.id"
              @click.prevent="handleChildNodeClick(subnode, subIndex)"
              class="node-l2"
              :class="{ 'node-l2-active' : (subIndex == activeChildNodeIndex)}"
            >{{ subnode.name }}</li>
          </ul>
        </transition>

js,这里是vue中的methods部分

    menuEnter: function(el, done) {
    //这行是关键
      el.offsetWidth;
      el.style.maxHeight =  this.nodes[this.activeParentNodeIndex].children.length * 4 + "rem";
      el.style.transition = "all 0.3s ease-in";
      done();
    },
    menuLeave: function(el) {
      el.offsetWidth;
      el.style.maxHeight = 0;
      el.style.transition = "all 0.3s ease-out";
    }

css:

//transitions
.default-enter-active {
    transition: all 0.3s ease-in;
}

.default-leave-active {
    transition: all 0.3s ease-out;
}

.default-enter,
.default-leave-to {
    max-height: 0;
}

说明

这里结合了js和css,其实只用js也可以,但是稍微麻烦。

只用css也可以,但是效果会稍微差一些(后面会解释)。


这里实现下拉和收起,利用的css的transition
vue中定义了三个状态,对应显示,分别是(事件/css类)

  • before-enter/v-enter:动画开始/初始状态
  • enter/v-enter-active:动画过程/中间状态
  • after-enter/v-enter-to:动画结束/结束状态

对于隐藏(leave)也同样

计算过度高度

这里对于显示,利用的是max-height属性,第一个关键点在于,初始状态max-height设置为0,在中间状态设置为下拉框的实际大小。这样才会出现高度变化的下拉效果。

这也就是为什么使用js hook,而不是直接使用css的原因呢,因为子菜单高度无法确切知道,如果对效果不敏感,可以直接指定一个较大的max-height,但是为了效果好,还是根据菜单长度确定过度最好。

控制页面刷新

第二个关键点在于 el.offsetWidth;这一句看似无用的代码,不加的话,浏览器不会有动画效果,加上以后,按照网上的说法,会强制触发绘制。

其实在vue的官方文档有提到

When using JavaScript-only transitions, the done callbacks are required for the enter and leave hooks. Otherwise, the hooks will be called synchronously and the transition will finish immediately.

但是我测试了一下,调用done()还是没有效果,不清楚原因。

原文地址:https://www.cnblogs.com/mosakashaka/p/12609236.html