Vue2 Starter

ES6 + Vue.js jsFiddle Starter Template by Christian Gambardella http://gambardella.info/2016/11/03/jsfiddle-starter-for-vue-js/

by kahiro okina

HTML

<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/bulma/0.2.3/css/bulma.min.css">
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/vue.js"></script>
<div id="app">
  <button @click="toggle1">とぐる1</button>

  <slide-up-down :active="active1" :closed-height="100">
    長い<br>
    長い<br>
    長い<br>
    長い<br>
    長い<br>
    長い<br>
    長い<br>
    長い<br>
    長い<br>
    長い<br>
    長い<br>
    長い<br>
    <button @click="toggle2">とぐる2</button>
    <slide-up-down :active="active2">
      いぇい!2
    </slide-up-down>
  </slide-up-down>
</div>

Babel + JSX

console.clear()

const SlideUpDown = {
  name: 'SlideUpDown',

  props: {
    active: Boolean,
    duration: {
      default: 500,
    },
    tag: {
      type: String,
      default: 'div',
    },
    closedHeight: {
      default: 0,
    },
  },

  data() {
    return {
      maxHeight: this.closedHeight,
      opened: false,
      isInitialized: false,
    };
  },

  render(h) {
    return h(
      this.tag,
      { style: this.style },
      this.$slots.default
    );
  },

  mounted() {
    window.addEventListener('resize', this.layout);
  },

  destroyed() {
    window.removeEventListener('resize', this.layout);
  },

  watch: {
    active: {
      handler() {
        this.layout();
      },
      immediate: true,
    },
  },

  computed: {
    style() {
      if (this.opened) return {};
      const baseStyle = {
        overflow: 'hidden',
        'max-height': `${this.maxHeight}px`,
      };

      if (this.isInitialized) {
        return Object.assign({}, baseStyle, {
          'transition-property': 'max-height',
          'transition-duration': `${this.duration}ms`,
        });
      }
      return baseStyle;
    },
  },

  methods: {
    layout() {
      if (this.active) {
        if (!this.isInitialized) {
          this.isInitialized = true;
          this.opened = true;
          return;
        } else {
          this.isInitialized = true;
          this.maxHeight = this.$el.scrollHeight;
          setTimeout(() => {
            if (this.active) {
              this.opened = true;
            }
          }, this.duration);
        }
      } else {
        if (!this.isInitialized) {
          this.isInitialized = true;
          return;
        }
        this.opened = false;
        this.maxHeight = this.$el.scrollHeight;
        this.$nextTick(() => {
          setTimeout(() => {
            if (!this.active) {
              if (this.maxHeight > this.closedHeight) {
                this.maxHeight = this.closedHeight;
              }
            }
...