custom image slider in vue js - javascript

Tryin to build a simple custom image slide and mostly make it work except one thing. When :src data changes, I want to add a transition like opacity:0 ~ 1 but couldn't achieve that part. Here is the slide.
template
<img class="slide-image" :src="getImgUrl(images[0])">
script
data(){
return {
images: [
"/images/home/home-slide1.png",
"/images/home/home-slide2.png",
"/images/home/home-slide3.png",
"/images/home/home-slide4.png",
"/images/home/home-slide5.png",
]
};
},
watch: {
getImgUrl(){
}
},
mounted(){
window.setInterval(()=>{
this.slide();
}, 5000);
},
methods: {
getImgUrl(im) {
return require('../assets' + im)
},
slide(){
let first = this.images.shift();
this.images = this.images.concat(first);
},
},
what is best and simple possible way to add a transition when :src changes every 5s, appreciate if anyone can guide about this.

<script>
export default {
name: "Slider",
data() {
return {
images: [
"/images/home/home-slide1.png",
"/images/home/home-slide2.png",
"/images/home/home-slide3.png",
"/images/home/home-slide4.png",
"/images/home/home-slide5.png",
],
timer: null,
currentIndex: 0
};
},
mounted: function() {
this.startSlide();
},
methods: {
startSlide: function() {
this.timer = setInterval(this.next, 5000);
},
next: function() {
this.currentIndex += 1;
},
prev: function() {
this.currentIndex -= 1;
}
},
computed: {
currentImg: function() {
return this.images[Math.abs(this.currentIndex) % this.images.length];
}
}
};
</script>
Let’s look what we did here:
We got an array of image URLs.
Set timer to null and set currentIndex to 0 for showing the first image.
Created startSlide function for sliding images every 4 seconds.
Created next and prev functions for sliding to the previous or the next image. According to the last currentImg function it detects which image must show at that time based on the index.
HTML:
<template>
<div>
<transition-group name="fade" tag="div">
<div v-for="i in [currentIndex]" :key="i">
<img :src="currentImg" />
</div>
</transition-group>
<a class="prev" #click="prev" href="#">❮ Previous</a>
<a class="next" #click="next" href="#">❯ Next</a>
</div>
</template>
Here we take advantage of the built-in transtion-group component that comes with Vue.js, then iterate images and add the functions we created earlier.
More details here: https://alligator.io/vuejs/create-image-slider/

You can try the Vue-transition
Wrap your transition section with transition tag like this
<transition name="slider">
<img class="slide-image" :src="getImgUrl(images[0])">
</transition>
It will add classes when the elements enter and leave. So you can add styles accordingly.
Please refer this link : https://v2.vuejs.org/v2/guide/transitions.html#Transitioning-Single-Elements-Components

Related

Reload vue-owl-carousel after dynamic data update

Initialized a vue-owl-carousel using dynamic data
<script>
import carousel from 'vue-owl-carousel'
export default {
components: { carousel },
}
<carousel :items="1">
<img v-for="(img, index) in images" :src="img" :key="index">
</carousel>
data: function() {
return {
images: [
"https://placeimg.com/200/200/any?1",
"https://placeimg.com/200/200/any?2",
"https://placeimg.com/200/200/any?3",
"https://placeimg.com/200/200/any?4"
]
};
}
Removed one of images from the images array
How to update the owl carousel with new images array?
This should work with normal reactivity so im guessing the way how the carousel library is built is just sloppy. My advice is to just build your own carousel. It is really not that and can be a good learning curve.
Nevertheless if you really want to use this library, you could wrap the carousel in a template with a v-if condition. Because when deleting a entry from the images array the carousel needs to be rerendered to show its changes. You can force this by deleting and adding the component to the DOM by toggling the v-if of the template tag. A hacky solution to a problem that shouldnt exist in the first place. But something like this would work:
<template>
<div id="app">
<template v-if="toggle">
<carousel :items="1">
<template v-for="(img, index) in images">
<img :src="img" :key="index" />
</template>
</carousel>
</template>
<button #click="deleteImage">DELETE A IMAGE</button>
</div>
</template>
<script>
import Carousel from "vue-owl-carousel";
export default {
name: "App",
components: { Carousel },
data() {
return {
images: [
"https://placeimg.com/200/200/any?1",
"https://placeimg.com/200/200/any?2",
"https://placeimg.com/200/200/any?3",
"https://placeimg.com/200/200/any?4",
],
toggle: true,
};
},
methods: {
deleteImage() {
this.toggle = false;
this.images.pop();
this.$nextTick(() => {
this.toggle = true;
});
},
},
};
</script>
Ive tested it and it works with the vue-owl-carousel library see sandbox

How to stop rendering a vue carousel component after all it's data is shown

As title says, I want to stop rendering a vue carousel component after it's data is shown or after x seconds. I haven't found any related information about this. I know it's quite... weird to do this, but still I want to know how to, for some projects. Here's the code:
<div class="col-md-12 col-sm-12 col latest-news max-width">
<carousel
:per-page="1"
:mouse-drag="false"
:autoplay="true"
:paginationEnabled="false"
:loop="true"
:speed="1500"
:autoplayTimeout="7000"
>
<slide v-for="post in posts_1" :post="post" :key="post.id">
<NewsTitle class="most-important" :post="post" :key="post.id" />
</slide>
</carousel>
</div>
Is this what do you need?
<template>
<carousel
v-if="showCarousel"
...
>
...
</carousel>
</template>
<script>
export default {
data: function(){
return {
showCarousel: true,
}
},
methods: {
hideCarousel: function(){
setTimeout(() => {
this.showCarousel = false;
}, 5000);
}
},
created: function(){
this.hideCarousel();
}
}
</script>
If you want to hide your carousel you should be dependent on showCarousel variable. Also you need to add condition v-if="showCarousel" to your carousel tag. My code should hide carousel after 5000 milliseconds or 5 seconds.

How to check if image is loaded in Vue/Nuxt?

New to Vue and Nuxt. I am trying to show skeletons before image is loaded completely.
Here's my attempt, skeleton shows but image is never loaded and onImageLoad is never called.
<template>
<div>
<img v-if="isLoaded" #load="onImgLoad" :src="me.img">
<div v-else class="skeleton"></div>
</div>
</template>
<script lang="ts">
export default {
props: {
me: Object,
},
data() {
return {
isLoaded: false,
}
},
methods: {
onImgLoad() {
console.log(` >> isLoaded:`, this.isLoaded)
return this.isLoaded = true
},
},
}
</script>
I have some broken image url to test fallback src, is it a problem? But I tried removing those broken links and it's still not working.
Example data:
export const me = {
name: 'David',
img: 'https//david.png', // Example broken > https://no.jpg
},
Please help me, what I am doing wrong?
Because isLoaded is false on the initial render, the img element is removed from the DOM tree. If it’s not in the DOM, the image src won’t be requested, ergo— no load event.
Switch to v-show. The img element will remain in the DOM, so the #load event will fire.

Vue.js: How to rerun your code whenever you change slides in your vue carousel

I am very new to vue.js and fumbling my way though it, forgive me if my terms are incorrect. I am creating a touchscreen application that needs to be ADA compliant (only the bottom part of the screen is accessible, so i have to use buttons for interaction).
I have a parent component with a carousel creating an array of slides, pulling data from my child component.
parent component HTML
<carousel :navigateTo="selectedListIndex" #pageChange="OnPageChange">
<slide v-for="(member, index) in selectedList" :key="index">
<MemberBioPage :member="member"/>
</slide>
</carousel>
parent component SCRIPT:
export default {
data () {
return {
currentPage: 0
}
},
components: {
MemberBioPage,
Carousel,
Slide
},
computed: {
selectedList () {
return this.$store.state.selectedList
},
selectedListIndex () {
return this.$store.state.selectedListIndex
}
},
methods: {
OnPageChange (newPageIndex) {
console.log(newPageIndex)
this.currentPage = newPageIndex
}
}
}
within my child component, i have bio copy being pulled from my data and arrow buttons that allow you to scroll the text. There is an outer container and an inner container to allow the scrolling and based on the height that the content takes up in the container will determine when the arrows disable or not.
child component HTML:
<div class="member-bio-page">
<div class="bio">
<div class="portrait-image">
<img :src="member.imgSrc" />
</div>
<div class="bio-container">
<div class="inner-scroll" v-bind:style="{top: scrollVar + 'px'}">
<h1>{{ member.name }}</h1>
<div class="description-container">
<div class="para">
<p v-html="member.shortBio"></p>
</div>
</div>
</div>
</div>
<div class="scroll-buttons">
<div>
<!-- set the class of active is the scroll variable is less than 0-->
<img class="btn-scroll" v-bind:class="{ 'active': scrollVar < 0 }" #click="scrollUp" src="#/assets/arrow-up.png">
</div>
<div>
<!-- set the class of active is the scroll variable is greater than the height of the scrollable inner container-->
<img class="btn-scroll" v-bind:class="{ 'active': scrollVar > newHeight }" #click="scrollDown" src="#/assets/arrow-down.png">
</div>
</div>
</div>
</div>
child component SCRIPT:
<script>
export default {
props: [
'member', 'currentPage'
],
data () {
return {
scrollVar: 0,
outerHeight: 0,
innerHeight: 0,
newHeight: -10
}
},
mounted () {
this.outerHeight = document.getElementsByClassName('bio-container')[0].clientHeight
this.innerHeight = document.getElementsByClassName('inner-scroll')[0].clientHeight
this.newHeight = this.outerHeight - this.innerHeight
return this.newHeight
},
methods: {
scrollUp () {
console.log(this.scrollVar)
this.scrollVar += 40
},
scrollDown () {
console.log(this.scrollVar)
this.scrollVar -= 40
},
showVideo () {
this.$emit('showContent')
}
}
}
</script>
I am able to get the height of the first bio i look at, but on page change it keeps that set height. I basically want the code in mounted to be able to rerun based on the index of the slide i am on. I need 'newHeight' to update on each page change. I tried grabbing the 'currentPage' from my parent component using props, but it pulls undefined.
here is all a snippet from my data to show you what data i currently have:
{
index: 12,
name: 'Name of Person',
carouselImage: require('#/assets/carousel-images/image.jpg'),
imgSrc: require('#/assets/bio-page-image-placeholder.jpg'),
shortBio: '<p>a bunch of text being pulled</p>',
pin: require('#/assets/image-of-pin.png')
}
this is also my store just in case
const store = new Vuex.Store({
state: {
foundersList: founders,
chairmanList: chairmans,
selectedList: founders,
selectedListIndex: -1
},
mutations: {
setSelectedState (state, list) {
state.selectedList = list
},
setSelectedListIndex (state, idx) {
state.selectedListIndex = idx
}
}
})
Alright, so this is a good start. Here's a few things I would try:
Move the code you currently have in mounted to a new method called calculateHeight or something similar.
Call the method from your scrollUp and scrollDown methods.
So your final code would look something like this:
export default {
props: [
'member', 'currentPage'
],
data () {
return {
scrollVar: 0,
outerHeight: 0,
innerHeight: 0,
newHeight: -10
}
},
mounted () {
this.calculateHeight();
},
methods: {
calculateHeight() {
this.outerHeight = document.getElementsByClassName('bio-container')[0].clientHeight
this.innerHeight = document.getElementsByClassName('inner-scroll')[0].clientHeight
this.newHeight = this.outerHeight - this.innerHeight
},
scrollUp () {
console.log(this.scrollVar)
this.scrollVar += 40
this.calculateHeight()
},
scrollDown () {
console.log(this.scrollVar)
this.scrollVar -= 40
this.calculateHeight()
},
showVideo () {
this.$emit('showContent')
}
}
}

Transition between two pages doesn't work with vue.js and GSAP

I've started to learn vue.js, and I want to do a transition using GSAP (and not css) between two pages, so I found those properties : v-on:enter, v-on:leave.
It seems that my v-on:enter animation is only working on the first call of my app. I don't see the "leave" animation, plus I have some duplicated content when the new page appears.
I've two questions here :
What am I missing ?
How can I start my v-on:enter animation when the DOM is fully loaded? (so far my animation starts even if my DOM is not fully loaded)
Here's the code I use on my App.vue file, thank you very much.
<template>
<div id="app">
<transition
appear
v-on:enter="enter"
v-on:leave="leave"
v-bind:css="false"
>
<router-view/>
</transition>
</div>
</template>
<script>
import { TweenMax } from "gsap/TweenMax";
export default {
name: 'App',
components: {
},
methods: {
enter(el, done) {
TweenMax.to('body', 1, {opacity:1, onComplete:done});
},
leave(el, done) {
TweenMax.to('body', 1, {opacity:0, onComplete:done});
}
}
}
</script>
Use the out-in transition mode to transition the current view out first, then when complete, the new view transitions in.
Create a beforeEnter method in your component methods option to set the target element opacity to 0.
Listen to the beforeEnter JavaScript hook by adding v-on:before-enter="beforeEnter" to the
transition component.
Unless there is a good reason to use body as your target element, use the view component el instead.
Revised code:
<template>
<div id="app">
<transition
appear
v-bind:css="false"
v-on:before-enter="beforeEnter"
v-on:enter="enter"
v-on:leave="leave"
>
<router-view/>
</transition>
</div>
</template>
<script>
import { TweenMax } from "gsap/TweenMax";
export default {
name: 'App',
components: {
},
methods: {
beforeEnter(el) {
TweenMax.set(el, { opacity: 0 });
},
enter(el, done) {
TweenMax.to(el, 1, { opacity:1, onComplete:done });
},
leave(el, done) {
TweenMax.to(el, 1, { opacity:0, onComplete:done });
}
}
}
</script>

Categories

Resources