slideshow met div's dmv scriptaculous

Gepubliceerd op: 23.I.2006 01:03 CET
Categorieën: javascript

Update: I’ve recently written a JQuery version of this slideshow. It operates in roughly the same way and is a lot simpler. You can find it on github.

Geïnspireerd door een post bij code snippets heb ik met een kopje koffie zitten klungelen met javascript. Ik wilde graag een OO versie en daarmee dus de mogelijkheid om meerdere slideshows gemakkelijk op een pagina te kunnen plaatsen. En, in tegenstelling tot de inspiratie bron wilde ik dat de foto’s inelkaar over zouden gaan. Het resultaat:

Maar hoe werkt het?

Net als de post van Peter is mijn code afhankelijk van prototype.js en effect.js van script.aculo.us. In plaats van Element.Fade en Element.Appear af te wisselen heb ik alle afbeeldingen opgestapeld (dmv z-index), laat ik de bovenste verdwijnen (met Element.Fade) en stop ik afbeeldingen die verdwenen zijn onder op.

De HTML is simpel, een div met wat “slide” div’s erin:

<div id="slideshow">
  <div class="slide">
    <img src="kokmeeuwen.jpg"/>
  </div>
  <div class="slide">
    <img src="binti.jpg"/>
  </div>
  <div class="slide">
    <img src="stoptrein.jpg"/>
  </div>
</div>

Met CSS worden de “slides” overelkaar heen geplaatst:

<style type="text/css">
  #slideshow {
    position: relative;
    width: 240px;
    height: 180px;
  }
  #slideshow div {
    position: absolute;
    top: 0;
    left: 0;
  }
</style>

Door middel van JavaScript krijgen de “slides” allemaal een andere z-index:

<script type="text/javascript">
  function Slideshow(slideshow, timeout) {
    this.slides = [];
    var nl = $(slideshow).getElementsByTagName('div');
    for (var i = 0; i < nl.length; i++) {
      if (Element.hasClassName(nl[i], 'slide')) {
        this.slides.push(nl[i]);
      }
    }
    for (var i = 0; i < this.slides.length; i++) {
      this.slides[i].style.zIndex = this.slides.length - i;
    }

Dan wordt de next functie getimed:

    this.timeout = timeout;
    this.current = 0;

    Element.show(slideshow);
    setTimeout((function(){this.next();}).bind(this), this.timeout + 850);
  }

Deze next functie schuift alle de z-index door:

  Slideshow.prototype = {
    next: function() {
      for (var i = 0; i < this.slides.length; i++) {
        var slide = this.slides[(this.current + i) % this.slides.length];
        slide.style.zIndex = this.slides.length - i;
      }

Laat dan de bovenste afbeelding zachtjes verdwijnen:

      Effect.Fade(this.slides[this.current], {

Gooit hem daarna onderop:

        afterFinish: function(effect) {
          effect.element.style.zIndex = 0;
          Element.show(effect.element);
          Element.setOpacity(effect.element, 1);
        }
      });

En zorgt dat de volgde “slide” getimed staan:

      this.current = (this.current + 1) % this.slides.length;
      setTimeout((function(){this.next();}).bind(this), this.timeout + 850);
    }
  }

En zo wordt nu een dia-presentatie geregistreerd:

  new Slideshow('slideshow', 3000);
</script>

Voor mij werkt dit onder Internet Explorer, Firefox, Safari, Omniweb en Opera (hoewel deze niet fade). Probeer het zelf, download de volgden javascripts en hang ze in een stukkie HTML zoals boven beschreven:

Tom @ 2 maanden

Safari doet het ook!

Erwin @ 3 maanden

Je script bevat een bug als er maar 2 afbeeldingen zijn, dan zijn namelijk tijdelijk de z-indexen van beide plaatjes 0 en knippert het geheel even. Dit is op te lossen met de volgende code.


for (var i = 0; i < this.slides.length; i++) {
      var slide = this.slides[(this.current + i) % this.slides.length];
      slide.style.zIndex = this.slides.length + 1 - i;
}

Dus: z-index 1 hoger dan de lengte en alle elementen veranderen zodat er nooit 2 keer 0 is.

Remco @ 3 maanden

Dank! Het probleem zat hem in i < this.slides.length - 1 er werd steeds een slide gemist waardoor er na een hele ronde 2 elementen z-index 0 hadden. Ik ga meteen het artikel aanpassen en slideshow.js.

Eric @ 4 maanden

This doesn’t work correctly if all images do not have the same dimensions. Is there a way around that?

Remco @ 4 maanden

Sure. Give the “slide” div’s the maximum size and give them an opaque background. For instance; if you have landscape and portret pictures of sizes 400×300 and 300×400, then your CSS might look like:


#slideshow {
  position: relative;
  width: 400px;
  height: 400px;
  background: white;
}
div.slide {
  width: 400px;
  height: 400px;
  background: white;
}

Checkout the site for my newborn son for an example.

Stard @ 6 maanden

Nice effect :)

Anoniempje @ 7 maanden

Hi,
It’s a very nice work…
I congratulate you.
Did you solve the problem at Safari and Opera browsers ?
Best regards.
Yusuf Akyol
Istanbul / Turkey

newbie @ 9 maanden

hoi,

ik vind het wel een mooi ding dat je daar hebt staan.
het probleem is, ik weet niet hoe ik dit in mijn joomla cms moet plaatsen.
kan iemand mij uitleggen?

hartelijk dank

Granger @ 10 maanden

Thank you.
Greetings from Mexico.

alsi@quicknet.nl @ 12 maanden

Hallo,
Ik ben bezig met mijn site en zou 10 slideshows op 1 pagina willen zetten, is dat mogelijk? En hoe plaats ik die bij de juiste afbeelding? Misschien iets te hoog gegrepen, maar ik wil het toch proberen….
Alvast bedankt! Groeten,Alet

Seppie @ meer dan 1 jaar

Remco bedankt voor je hulp!
http://www.primaveraquint.nl

groetjes
Seppie

Anoniempje @ meer dan 1 jaar

bedankt