Vue 2.0 Hello World

by Max Sinev

HTML

<script src="https://unpkg.com/vue"></script>

<div id="app">
  <p>{{ message }}</p>
  <swim :items="items">
    <template v-slot:item="{ item }">
      <div class="item-wrapper">
        <div class="item">
          {{ item }}
        </div>
      </div>
    </template>
  </swim>
  <button @click="add">add</button>
</div>

<script type="text/x-template" id="atempl">
  <div :style="listParentStyle"
    class="vue-swimlane">
    <ul :style="listStyle">
      <li ref="items"
        v-for="(item, index) in internalItems"
        :key="index">
        <slot name="item" :item="item"></slot>
      </li>
    </ul>
  </div>
</script>

CSS

.vue-swimlane {
  width: 100%;
  overflow: hidden;
  padding: 0;
  margin: 0;
}

.vue-swimlane ul {
  list-style: none;
  padding: 0;
  margin: 0;
  text-align: center;
  transform: translateY(0);
  will-change: transform;
}

.vue-swimlane ul li {
  padding: 0;
  margin: 0;
}

.item-wrapper {
  padding-bottom: 20px;
}

.item {
  background: #ccc;
  padding: 10px;
}

JavaScript

let a = {
  name: 'VueSwimlane',
  template: '#atempl',
  props: {
    items: {
      type: Array,
      required: true,
    },
    rows: {
      type: Number,
      default: 3,
    },
    scale: {
      type: Number,
      default: 1,
    },
    transitionDuration: {
      type: Number,
      default: 500,
    },
    transitionDelay: {
      type: Number,
      default: 1200,
    },
    transition: {
      type: String,
      default: 'ease-out',
    },
    circular: {
      type: Boolean,
      default: false,
    },
  },
  data() {
    return {
      listTop: 0,
      moveUp: true,
      internalItems: [],
      currentIndex: 0,
      enabledTransition: false,
      itemHeight: 0,
      updatetimeoutId: null,
    }
  },
  computed: {
    transitionDelayNormalized() {
      return Math.abs(this.transitionDelay || 25)
    },
    transitionDurationNormalized() {
      return Math.abs(this.transitionDuration || 25)
    },
    itemScaleNormalized() {
      return Math.abs(this.scale || 1)
    },
    itemRowsNormalized() {
      return this.rows > this.items.length
        ? this.items.length
        : Math.abs(this.rows || 1)
    },
    listStyle() {
      return {
      	transform: `translateY(${this.listTop}px)`,
        transition: this.enabledTransition ? `transform ${this.transitionDurationNormalized}ms ${this.transition} !important` : 'none'
      };
    },
    listParentStyle() {
    	return `height: ${this.itemHeight * this.itemRowsNormalized}px`;
    }
  },
  created() {
  	this.internalItems = this.items.slice();
  },
  mounted() {
  	this.itemHeight = this.$refs.items[0].offsetHeight;
    //this.animate();
  },
  watch: {
  	items() {
    	this.internalItems = this.items.slice();
    	this.updateState();
    }
  },
  methods: {
    updateState(callback) {
    	this.enabledTransition = false;
    	this.$nextTick(() => {
      
      	if (this.currentIndex > 0) {
          //this.enabledTransition = false;
          this.listTop = 0;
         ...