<html>
<head>
<script src="https://cdn.jsdelivr.net/npm/vue@2.6.14/dist/vue.js"></script>
</head>
<body>
<h2>Vue Js Image swipe (left, right) using touch</h2>
<div id="app">
<div ref="swipeArea" class="swipe-area">
<img v-bind:src="currentImage" alt="Swipe left or right">
<div class="bottom-btns">
<button v-for="(image, index) in images" :key="index" :class="{ active: index === currentIndex }"
@click="currentIndex = index"></button>
</div>
<p>{{currentIndex+1}}/{{images.length}}</p>
</div>
</div>
<script>
new Vue({
el: '#app',
data() {
return {
images: [
'https://placekitten.com/400/400',
'https://placebear.com/400/400',
'https://placeimg.com/400/400/nature',
],
currentIndex: 0,
};
},
mounted() {
const swipeArea = this.$refs.swipeArea;
let touchstartX = 0;
let touchstartY = 0;
let touchendX = 0;
let touchendY = 0;
const threshold = 50; // minimum distance required to register a swipe
swipeArea.addEventListener('touchstart', (event) => {
touchstartX = event.changedTouches[0].screenX;
touchstartY = event.changedTouches[0].screenY;
}, false);
swipeArea.addEventListener('touchend', (event) => {
touchendX = event.changedTouches[0].screenX;
touchendY = event.changedTouches[0].screenY;
const deltaX = touchendX - touchstartX;
const deltaY = touchendY - touchstartY;
if (Math.abs(deltaX) > threshold && Math.abs(deltaY) < threshold) {
this.handleSwipe(deltaX > 0 ? 'right' : 'left');
}
}, false);
},
computed: {
currentImage() {
return this.images[this.currentIndex];
},
},
methods: {
handleSwipe(direction) {
const newIndex =
direction === "right"
? (this.currentIndex - 1 + this.images.length) % this.images.length
: (this.currentIndex + 1) % this.images.length;
const currentImageEl = this.$refs.swipeArea.querySelector("img");
currentImageEl.classList.add("fade");
setTimeout(() => {
this.currentIndex = newIndex;
currentImageEl.classList.remove("fade");
}, 500);
}
},
});
</script>
<style scoped>
.swipe-area {
position: relative;
width: 100%;
height: 400px;
/* You can adjust this to your desired height */
overflow: hidden;
}
.swipe-area img {
position: absolute;
width: 100%;
height: 100%;
object-fit: cover;
transition: opacity 0.5s ease-in-out;
opacity: 1;
}
.swipe-area img.fade {
opacity: 0.5;
}
.swipe-area p {
position: absolute;
top: 10px;
right: 10px;
font-size: 0.8rem;
font-weight: bold;
color: #fff;
background-color: rgba(0, 0, 0, 0.6);
padding: 4px 8px;
border-radius: 15px;
text-align: center;
z-index: 1;
}
.bottom-btns {
position: absolute;
bottom: 20px;
left: 50%;
transform: translateX(-50%);
display: flex;
justify-content: center;
}
.bottom-btns button {
width: 10px;
height: 10px;
border-radius: 50%;
margin: 0 6px;
background-color: #e5e5e5;
border: none;
}
.bottom-btns button.active {
background-color: #262626;
}
</style>
</body>
</html>