vueでカルーセルスライダー
vue.jsでカルーセルタイプのスライダーを作ってみた。ボタンをクリックすると回転するタイプ。
自動で回り続けるタイプもちょっと改造すれば作れると思う。
v-ifで次に表示される可能性のある要素までは実在させていますが、v-showで全ての要素を実在させておいても良いかと思います。
作りとしては、vueは2でもイケるはず。(コードはvue3)
HTMLは下記の通り
<main>
<header>
<button type="button" v-on:click="movePanels(1)">1へ</button>
<button type="button" v-on:click="movePanels(2)">2へ</button>
<button type="button" v-on:click="movePanels(3)">3へ</button>
<button type="button" v-on:click="movePanels(4)">4へ</button>
<button type="button" v-on:click="movePanels(5)">5へ</button>
<button type="button" v-on:click="movePanels(6)">6へ</button>
</header>
<section id="sec01" v-if="[6, 1, 2].includes(panel) || panel_check < 0" v-bind:class="{'moveLeftPanel':panel == 2, 'moveMiddlePanel':panel == 1, 'moveRightPanel':panel == 6, 'moveMiddle2Right':panel == 1 && panel_next == 6, 'moveMiddle2Left':panel == 1 && panel_next == 2, 'moveRight2Middle':panel == 6 && panel_next == 1, 'moveLeft2Middle':panel == 2 && panel_next == 1}" v-on:animationend="movePanel($event)">A</section>
<section id="sec02" v-if="[1, 2, 3].includes(panel) || panel_check < 0" v-bind:class="{'moveLeftPanel':panel == 3, 'moveMiddlePanel':panel == 2, 'moveRightPanel':panel == 1, 'moveMiddle2Right':panel == 2 && panel_next == 1, 'moveMiddle2Left':panel == 2 && panel_next == 3, 'moveRight2Middle':panel == 1 && panel_next == 2, 'moveLeft2Middle':panel == 3 && panel_next == 2}" v-on:animationend="movePanel($event)">B</section>
<section id="sec03" v-if="[2, 3, 4].includes(panel) || panel_check < 0" v-bind:class="{'moveLeftPanel':panel == 4, 'moveMiddlePanel':panel == 3, 'moveRightPanel':panel == 2, 'moveMiddle2Right':panel == 3 && panel_next == 2, 'moveMiddle2Left':panel == 3 && panel_next == 4, 'moveRight2Middle':panel == 2 && panel_next == 3, 'moveLeft2Middle':panel == 4 && panel_next == 3}" v-on:animationend="movePanel($event)">C</section>
<section id="sec04" v-if="[3, 4, 5].includes(panel) || panel_check < 0" v-bind:class="{'moveLeftPanel':panel == 5, 'moveMiddlePanel':panel == 4, 'moveRightPanel':panel == 3, 'moveMiddle2Right':panel == 4 && panel_next == 3, 'moveMiddle2Left':panel == 4 && panel_next == 5, 'moveRight2Middle':panel == 3 && panel_next == 4, 'moveLeft2Middle':panel == 5 && panel_next == 4}" v-on:animationend="movePanel($event)">D</section>
<section id="sec05" v-if="[4, 5, 6].includes(panel) || panel_check < 0" v-bind:class="{'moveLeftPanel':panel == 6, 'moveMiddlePanel':panel == 5, 'moveRightPanel':panel == 4, 'moveMiddle2Right':panel == 5 && panel_next == 4, 'moveMiddle2Left':panel == 5 && panel_next == 6, 'moveRight2Middle':panel == 4 && panel_next == 5, 'moveLeft2Middle':panel == 6 && panel_next == 5}" v-on:animationend="movePanel($event)">E</section>
<section id="sec06" v-if="[5, 6, 1].includes(panel) || panel_check < 0" v-bind:class="{'moveLeftPanel':panel == 1, 'moveMiddlePanel':panel == 6, 'moveRightPanel':panel == 1, 'moveMiddle2Right':panel == 6 && panel_next == 5, 'moveMiddle2Left':panel == 6 && panel_next == 1, 'moveRight2Middle':panel == 5 && panel_next == 6, 'moveLeft2Middle':panel == 1 && panel_next == 6}" v-on:animationend="movePanel($event)">F</section>
</main>
JSは下記の通り
<script type="module">
import { createApp } from 'https://unpkg.com/vue@3/dist/vue.esm-browser.js';
const vueApp = createApp({
data() {
return {
panel: 1,
panel_next: 0,
panel_target: 0,
panel_direction: 0,
panel_check: -1,
}
},
mounted() {
this.panel_check = document.querySelectorAll('main section').length;
},
methods: {
movePanels: function(targetPanel, event){
let interval = Math.abs(targetPanel - this.panel);
let chk1 = ( targetPanel > this.panel ) ? 1 : -1;
let chk2 = ( interval > (this.panel_check / 2) ) ? -1 : 1;
this.direction = chk1 * chk2;
this.panel_next = (this.panel + this.direction == 0 || this.panel + this.direction == this.panel_check) ? this.panel_check : (this.panel + this.direction) % this.panel_check;
this.panel_target = targetPanel;
},
movePanel: function(event){
for(let className of event.currentTarget.classList){
if( ['moveRight2Middle', 'moveLeft2Middle'].includes(className) ){
this.panel = this.panel_next != 0 ? this.panel_next : this.panel;
if( this.panel_next == this.panel_target ){
this.panel_target = 0;
this.panel_next = 0;
} else{
this.panel_next = (this.panel + this.direction == 0 || this.panel + this.direction == this.panel_check) ? this.panel_check : (this.panel + this.direction) % this.panel_check;
}
};
};
},
},
}).mount('main');
</script>
CSS(SCSS)は下記の通り
header {
width: 100vw;
position: fixed;
top: 0;
left: 0;
display: flex;
z-index: 10;
}
main {
width: 100vw;
height: 100vh;
overflow-x: hidden;
position: relative;
section {
width: 100vw;
min-width: 100vw;
height: 100vh;
sec01 { background-color: bisque; }
sec02 { background-color: paleturquoise; }
sec03 { background-color: plum; }
sec04 { background-color: honeydew; }
sec05 { background-color: plum; }
sec06 { background-color: coral; }
}
}
.moveLeftPanel {
position: absolute;
left: -100vw;
}
.moveMiddlePanel {
position: absolute;
left: 0;
}
.moveRightPanel {
position: absolute;
left: 100vw;
}
.moveRight2Middle {
animation-name: rigth2middle;
animation-duration: 0.2s;
animation-timing-function: ease-in-out;
}
.moveLeft2Middle {
animation-name: left2middle;
animation-duration: 0.2s;
animation-timing-function: ease-in-out;
}
.moveMiddle2Right {
animation-name: middle2rigth;
animation-duration: 0.2s;
animation-timing-function: ease-in-out;
}
.moveMiddle2left {
animation-name: middle2left;
animation-duration: 0.2s;
animation-timing-function: ease-in-out;
}
@keyframes rigth2middle {
0% { left: 100vw; }
100% { left: 0; }
}
@keyframes left2middle {
0% { left: -100vw; }
100% { left: 0; }
}
@keyframes middle2rigth {
0% { left: 0; }
100% { left: 100vw; }
}
@keyframes middle2left {
0% { left: 0; }
100% { left: -100vw; }
}