美文网首页Vue cli3 学习
vue实现collapse折叠板动画,可设置动画时间,动画延迟等

vue实现collapse折叠板动画,可设置动画时间,动画延迟等

作者: 一颗数据小白菜 | 来源:发表于2020-02-25 11:39 被阅读0次

    之前封装手风琴的时候借鉴列element做了个collapse折叠板动画。

    网上有个大神也做了个collapse折叠板动画。传送门这里赞最多的就是element的那个动画。

    我的那个element动画也是这个,vue 自定义指令封装一个手风琴嵌套组件这里的组件过度动画

    但是这个动画并不支持设置时间,进一步封装还是可以的。

    重写了一个collapse 的动画。

    效果如下


    collapse.gif 设置延时和动画时间.gif

    新建collapseMixins.js,内容如下

    export default {
      inheritAttrs: false,
      props: {
        duration: {
          type: [Number, Object],
          default: 300
        },
        delay: {
          type: [Number, Object],
          default: 0
        },
        group: Boolean,
        tag: {
          type: String,
          default: "span"
        },
        origin: {
          type: String,
          default: ""
        },
        styles: {
          type: Object,
          default: () => {
            return {
              animationFillMode: "both",
              animationTimingFunction: "ease-out"
            };
          }
        }
      },
      computed: {
        componentType() {
          return this.group ? "transition-group" : "transition";
        },
        hooks() {
          return {
            ...this.$listeners,
            beforeEnter: this.beforeEnter,
            afterEnter: el => {
              this.cleanUpStyles(el);
              this.$emit("after-enter", el);
            },
            beforeLeave: this.beforeLeave,
            leave: this.leave,
            afterLeave: el => {
              this.cleanUpStyles(el);
              this.$emit("after-leave", el);
            }
          };
        }
      },
      methods: {
        beforeEnter(el) {
          let enterDuration = this.duration.enter
            ? this.duration.enter
            : this.duration;
          el.style.animationDuration = `${enterDuration}ms`;
    
          let enterDelay = this.delay.enter ? this.delay.enter : this.delay;
          el.style.animationDelay = `${enterDelay}ms`;
    
          this.setStyles(el);
          this.$emit("before-enter", el);
        },
        cleanUpStyles(el) {
          Object.keys(this.styles).forEach(key => {
            const styleValue = this.styles[key];
            if (styleValue) {
              el.style[key] = "";
            }
          });
          el.style.animationDuration = "";
          el.style.animationDelay = "";
        },
        beforeLeave(el) {
          let leaveDuration = this.duration.leave
            ? this.duration.leave
            : this.duration;
          el.style.animationDuration = `${leaveDuration}ms`;
    
          let leaveDelay = this.delay.leave ? this.delay.leave : this.delay;
          el.style.animationDelay = `${leaveDelay}ms`;
    
          this.setStyles(el);
          this.$emit("before-leave", el);
        },
        leave(el, done) {
          this.setAbsolutePosition(el);
          this.$emit("leave", el, done);
        },
        setStyles(el) {
          this.setTransformOrigin(el);
          Object.keys(this.styles).forEach(key => {
            const styleValue = this.styles[key];
            if (styleValue) {
              el.style[key] = styleValue;
            }
          });
        },
        setAbsolutePosition(el) {
          if (this.group) {
            el.style.position = "absolute";
          }
          return this;
        },
        setTransformOrigin(el) {
          if (this.origin) {
            el.style.transformOrigin = this.origin;
          }
          return this;
        }
      }
    };
    

    建立一个collapseTransition.js,内容如下

    import Vue from "../utils/vue";
    import collapseMixins from "./collapseMixins";
    
    const name = "NlyCollapseTransition";
    
    export const NlyCollapseTransition = Vue.extend({
      name: name,
      mixins: [collapseMixins],
      methods: {
        transitionStyle(duration = 300) {
          let durationInSeconds = duration / 1000;
          let style = `${durationInSeconds}s height ease-in-out, ${durationInSeconds}s padding-top ease-in-out, ${durationInSeconds}s padding-bottom ease-in-out`;
          return style;
        },
        beforeEnter(el) {
          let enterDuration = this.duration.enter
            ? this.duration.enter
            : this.duration;
          el.style.transition = this.transitionStyle(enterDuration);
          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;
          this.setStyles(el);
        },
    
        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";
        },
    
        afterEnter(el) {
          el.style.transition = "";
          el.style.height = "";
          el.style.overflow = el.dataset.oldOverflow;
        },
    
        beforeLeave(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";
          this.setStyles(el);
        },
    
        leave(el) {
          let leaveDuration = this.duration.leave
            ? this.duration.leave
            : this.duration;
          if (el.scrollHeight !== 0) {
            // for safari: add class after set height, or it will jump to zero height suddenly, weired
            el.style.transition = this.transitionStyle(leaveDuration);
            el.style.height = 0;
            el.style.paddingTop = 0;
            el.style.paddingBottom = 0;
          }
          // necessary for transition-group
          this.setAbsolutePosition(el);
        },
    
        afterLeave(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;
        }
      },
      render(h) {
        return h(
          "transition",
          {
            props: {
              is: this.componentType,
              tag: this.tag
            },
            on: {
              "before-enter": this.beforeEnter,
              "after-enter": this.afterEnter,
              enter: this.enter,
              "before-leave": this.beforeLeave,
              leave: this.leave,
              "after-leave": this.afterLeave
            }
          },
          this.$slots.default
        );
      }
    });
    

    collapseMixins.js是一个混合类,因为我封装了其他不同类型的动画,所以做了一个mixins。

    使用的时候引入collapseTransition组件就行。

    <collapse-transition>
      <div v-show="show">
          ...
      </div>
    </collapse-transition>
    

    相关文章

      网友评论

        本文标题:vue实现collapse折叠板动画,可设置动画时间,动画延迟等

        本文链接:https://www.haomeiwen.com/subject/pjpzqhtx.html