Home > Blockchain >  Slideshow with fade animation
Slideshow with fade animation

Time:12-26

How can I adjust this code so that it doesn't fade out straight away? In other words, make the image fade in, sit for a few seconds and then fade back out?

This is my code right now:

    <div id="slideshow-example" data-component="slideshow">
        <div role="list">
            <div >
                <img src="https://images.unsplash.com/photo-1486312338219-ce68d2c6f44d?w=752&ixid=dW5zcGxhc2guY29tOzs7Ozs=" alt="">
            </div>
            <div >
                <img src="https://images.unsplash.com/photo-1488590528505-98d2b5aba04b?w=750&ixid=dW5zcGxhc2guY29tOzs7Ozs=" alt="">
            </div>
            <div >
                <img src="https://images.unsplash.com/photo-1498753427761-548428edfa67?w=889&ixid=dW5zcGxhc2guY29tOzs7Ozs=" alt="">
            </div>
        </div>
    </div>

[data-component="slideshow"] .slide {
    display: none;
  text-align: center;
}

[data-component="slideshow"] .slide.active {
    display: block;
}

.fade
{
    -webkit-animation: fadeinout 2s linear forwards;
    animation: fadeinout 2s linear forwards;
}

@-webkit-keyframes fadeinout {
    0%,100% { opacity: 0; }
    50% { opacity: 1; }
  }
  
@keyframes fadeinout {
  0%,100% { opacity: 0; }
  50% { opacity: 1; }
}

var slideshows = document.querySelectorAll('[data-component="slideshow"]');
slideshows.forEach(initSlideShow);

function initSlideShow(slideshow) {

    var slides = document.querySelectorAll(`#${slideshow.id} [role="list"] .slide`);

    var index = 0, time = 5000;
    slides[index].classList.add('active');

    setInterval( () => {
        slides[index].classList.remove('active');
        
        index  ;
        if (index === slides.length) index = 0;

        slides[index].classList.add('active');

    }, time);
}

Please ignore this part, StackOverflow won't let me post because it's "mostly code" even though there's not much more of an explanation I can give towards my issue. If you are confused on my issue however, just ask me and I'll try and explain it more in-depth.

CodePudding user response:

You can change the percentage of which the element is shown something like the following:

var slideshows = document.querySelectorAll('[data-component="slideshow"]');
slideshows.forEach(initSlideShow);

function initSlideShow(slideshow) {

    var slides = document.querySelectorAll(`#${slideshow.id} [role="list"] .slide`);

    var index = 0, time = 5000;
    slides[index].classList.add('active');

    setInterval( () => {
        slides[index].classList.remove('active');
        
        index  ;
        if (index === slides.length) index = 0;

        slides[index].classList.add('active');

    }, time);
}
[data-component="slideshow"] .slide {
    display: none;
  text-align: center;
}

[data-component="slideshow"] .slide.active {
    display: block;
}

.fade
{
    -webkit-animation: fadeinout 3s linear forwards;
    animation: fadeinout 2s linear forwards;
}

@-webkit-keyframes fadeinout {
    0%,100% { opacity: 0; }
    20%, 80% { opacity: 1; }
  }
  
@keyframes fadeinout {
  0%,100% { opacity: 0; }
  20%,50% { opacity: 1; }
}
    <div id="slideshow-example" data-component="slideshow">
        <div role="list">
            <div >
                <img src="https://images.unsplash.com/photo-1486312338219-ce68d2c6f44d?w=752&ixid=dW5zcGxhc2guY29tOzs7Ozs=" alt="">
            </div>
            <div >
                <img src="https://images.unsplash.com/photo-1488590528505-98d2b5aba04b?w=750&ixid=dW5zcGxhc2guY29tOzs7Ozs=" alt="">
            </div>
            <div >
                <img src="https://images.unsplash.com/photo-1498753427761-548428edfa67?w=889&ixid=dW5zcGxhc2guY29tOzs7Ozs=" alt="">
            </div>
        </div>
    </div>

CodePudding user response:

Here is a brief re-write of your project using async await syntax and some different logic.

First, I use two helper functions. One is a signature $ function similar to jQuery, but just to shorted grabbing things from the document. I also allow another element to be passed as the parent we are selecting things from because I feel it makes the code more readable. The other is a wait function similar to Python's sleep. There are better resources for understanding promises, but in short, any function that is called async function will allow the await keyword to "wait" for a promise to resolve.

Next, I use an anonymous arrow function passed which calls the function instead of just passing the name of the function. The reason I do this is to explicitly state which arguments from the forEach method I am passing into my function. If we do not do this, the second argument slides would be passed an index which would not be intended.

Inside the function initSlideShow we check to see if slides are defined, and if not we define it. This way we dont have to use query selector to grab things each iteration, and instead can reuse the previous values on recursive calls.

we set the time we will use later

we start looping through each slide, and first add active which will change the display to block. We need to allow the dom to render the change before fading in, so we wait 10 ms. then we remove the fade class which removes the opacity 0, and the transition css makes it fade in over 1s.

We wait the amount of time specified.

We add the fade class back to the element.

We wait the animation time we remove active, which sets display to none.

After we loop through all the slides, we just call the function again passing the slides we already fetched to do it again. A nice little recursive logic to loop the function forever.

If you have any questions regarding the code, please ask.

const $ = (str, dom = document) => [...dom.querySelectorAll(str)];
const wait = t => new Promise(r => setTimeout(r, t));

const slideshows = $('[data-component="slideshow"]');
slideshows.forEach(el => initSlideShow(el));

async function initSlideShow(container, slides) {
  if (slides == undefined) slides = $('[role="list"] .slide', container);
  const time = 5000;
  
  for (const slide of slides) {
    slide.classList.add("active");
    await wait(10);
    slide.classList.remove("fade");
    await wait(time);
    slide.classList.add("fade");
    await wait(1000);
    slide.classList.remove("active");
  }
  initSlideShow(container, slides);
}
[data-component="slideshow"] .slide {
    display: none;
    text-align: center;
    transition: opacity 1s;
}

[data-component="slideshow"] .slide.active {
    display: block;
}

.fade {
  opacity: 0;
}
<div id="slideshow-example" data-component="slideshow">
    <div role="list">
        <div >
            <img src="https://images.unsplash.com/photo-1486312338219-ce68d2c6f44d?w=752&ixid=dW5zcGxhc2guY29tOzs7Ozs=" alt="">
        </div>
        <div >
            <img src="https://images.unsplash.com/photo-1488590528505-98d2b5aba04b?w=750&ixid=dW5zcGxhc2guY29tOzs7Ozs=" alt="">
        </div>
        <div >
            <img src="https://images.unsplash.com/photo-1498753427761-548428edfa67?w=889&ixid=dW5zcGxhc2guY29tOzs7Ozs=" alt="">
        </div>
    </div>
</div>

There are many things I would do differently in an actual production app though. Changing display none to block frequently like this will likely shift the layout of the page unpredictable. I would stick to changing opacity and transition mainly. Maybe sliding the elements inside a container with hidden overflow when faded out.

  • Related