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;
...