用JavaScript制作快速运行的图像幻灯片?

时间:2012-02-11 13:11:02

标签: javascript html slideshow

我正在使用原生JS制作图像幻灯片。
我决定自己创建,因为它需要以~100ms的间隔运行,并且没有任何特殊的过渡效果(请参阅here),所以我认为没有必要像JQuery一样包含一个像JQuery这样的大型库应用。
这是我目前使用的代码[编辑:原始代码 - 现已修改]:

// JavaScript Document
function preloadimages(arr){ // the preloadimages() function is adapted from http://www.javascriptkit.com/javatutors/preloadimagesplus.shtml
    var newimages = [], loadedimages = 0;
    var postaction = function() {};
    var arr = (typeof arr != "object") ? [arr] : arr;
    function imageloadpost() {
        loadedimages++;
        if (loadedimages == arr.length) {
            postaction(newimages); //call postaction and pass in newimages array as parameter
        }
    }
    for (var i = 0; i < arr.length; i++) {
        newimages[i] = new Image();
        newimages[i].src = arr[i];
        newimages[i].onload = function() {
            imageloadpost();
        }
        newimages[i].onerror = function() {
            imageloadpost();
        }
    }
    return { //return blank object with done() method
        done: function(f) {
            postaction = f || postaction; //remember user defined callback functions to be called when images load
        }
    }
}

/* USAGE:
preloadimages(['ed.jpg', 'fei.jpg', 'budapest.gif', 'duck.jpg']).done(function(images) {
    images.sort(function(a, b) {
        return a.width - b.width; //sort images by each image's width property, ascending
    });
    alert(images[0].src); //alerts the src of the smallest image width wise
});
*/

function animateSlideshow() {
    var num = window.imgNum + 1 ;
    if (num >= d['imgs'].length) {
        num = 0;
    }
    window.imgNum = num;
    imgTag.src = d['imgs'][num];
    var t = window.setTimeout(function(){animateSlideshow(imgNum, imgTag, d)}, 100);
}

var d;
var imgTag;
var imgNum = 0;
$.onDomReady (function () { // This is not JQuery, it's a simple cross-browser library which you can read here: http://assets.momo40k.ch/common/js/$.js
    // data is an array that should be already defined on the calling page,
    // containing all the necessary information to generate all the rotation slideshows on the page
    for (i = 0; i < data.length; i++) {
        d = data[i];
        var div = document.getElementById(d['id']);
        imgTag = $.Elements.getElementsByClassName('theImage', div)[0];

        // preload the images...
        preloadimages(d['imgs']).done(function(images) {
            imgTag.src = d['imgs'][0];
            animateSlideshow();
        });
    }

});



<!-- HTML calling JS Scripts -->
... HTML document ...
<script src="http://assets.momo40k.ch/common/js/$-min.js" language="javascript" type="text/javascript"></script>
<script language="javascript" type="text/javascript">

var data = [];

// I would have an index for each slideshow on the page
data[0] = [];
data[0]['id'] = 'rotation2';// the ID of the tag the initial image is in
data[0]['imgs'] = ['http://www.momo40k.ch/images/pages/stefan_lehmann/bat/pic1.png',
    'http://www.momo40k.ch/images/pages/stefan_lehmann/bat/pic2.png',
    'http://www.momo40k.ch/images/pages/stefan_lehmann/bat/pic3.png',
    '... all the images ... '];

</script>
<script src="js/rotation.js" language="javascript" type="text/javascript"></script>
</body>
</html>



这是初始图像的标签如下:

<div id="rotation2" class="rotation blackbg">
    <img src="http://www.momo40k.ch/images/pages/stefan_lehmann/bat/pic1.png" width="300" title="" class="theImage" />
</div>





现在提问: 这个脚本只允许我在页面上有一个单独的“幻灯片放映” - 因为在循环的每次迭代中它都会覆盖imgNum变量。有没有其他更好的方式来做这个幻灯片放映(如果可能没有JQuery,否则没问题),即使是以完全不同的方式? 谢谢

编辑:我按照Jared Farrish的回答重新编写了剧本,现在工作正常!

1 个答案:

答案 0 :(得分:1)

我在您的代码或方法中遇到了一些问题,因此我决定使用我将采用的方法重做它。例如:

  1. 我会使用document.images来获取所有图片,对于那些具有旋转器特定className的图片,我需要识别(domElement.parentNode)并获取包含div的图片,这将给我id
  2. 我会使用parentNode.id图片的class="rotation"创建一个带有集合的对象(通过容器id)我可以用来存储对img个节点的引用
  3. 使用闭包范围不在全局范围内,并且能够在闭包范围函数之间共享变量。
  4. 使用变量函数来设置处理程序和回调函数。
  5. 如果您有任何问题或发现无法解决的问题,请与我们联系。

    <div id="rotator1" class="rotation blackbg">
        <img class="slides" src="http://upload.wikimedia.org/wikipedia/commons/6/6e/Brandenburger_Tor_2004.jpg" />
        <img class="slides" src="http://upload.wikimedia.org/wikipedia/commons/a/ad/Cegonha_alsaciana.jpg" />
        <img class="slides" src="http://upload.wikimedia.org/wikipedia/commons/d/da/CrayonLogs.jpg" />
    </div>
    <div id="rotator2" class="rotation blackbg">
        <img class="slides" src="http://upload.wikimedia.org/wikipedia/commons/1/17/Bobbahn_ep.jpg" />
        <img class="slides" src="http://upload.wikimedia.org/wikipedia/commons/9/90/DS_Citro%C3%ABn.jpg" />
        <img class="slides" src="http://upload.wikimedia.org/wikipedia/commons/f/f0/DeutzFahr_Ladewagen_K_7.39.jpg" />
        <img class="slides" src="http://upload.wikimedia.org/wikipedia/commons/c/c7/DenglerSW-Peach-faced-Lovebird-20051026-1280x960.jpg" />
        <img class="slides" src="http://upload.wikimedia.org/wikipedia/commons/4/4d/FA-18F_Breaking_SoundBarrier.jpg" />
    </div>
    
    var slideshows = function(){
        var timeouts = {},
            imgs;
    
        function preloadImages(list){
            var loading = list,
                img,
                loaded = {},
                newimages = [];
    
            var imageloaded = function(){
                // this here is one of the new Image()s we created
                // earlier; it's not the "real" image on the screen.
                // So I put the reference to the actual image it represents
                // on the screen in the rel attribute so I can use it's
                // reference; I just have to use this.rel to get it.
                var parent = this.rel.parentNode;
    
                // Keeping track of the individual sets loaded.
                loaded[parent.id]++;
    
                // Here is where this/self gets it's context from, when
                // we .call(parent, 0). It's the parentNode to the image
                // we've referenced above. This should only run once,
                // when the last image has loaded for the set.
                if (loaded[parent.id] == loading[parent.id].length) {
                    animateSlideshow.call(parent, 0);
                }
            };
    
            var imagenotloaded = function(){
                // this.rel is the reference to the actual image we
                // have in the DOM, so we'll set the error flag on it.
                this.rel['imageerror'] = true;
                imageloaded.call(this);
            };
    
            for (var load in loading) {
                // loaded is equivalent to imgs.sets, so load is the
                // id for the container.
                loaded[load] = [];
    
                // Now we're going to loop over every image in the
                // current set, creating a Javascript image object
                // to initiate the download of the file and tell us
                // when it's finished. Not the newimages[i].rel = img
                // part.
                for (var i = 0, l = loading[load].length; i < l; i++) {
                    img = loading[load][i];
                    newimages[i] = new Image();
                    newimages[i].onload = imageloaded;
                    newimages[i].onerror = imagenotloaded;
                    newimages[i].rel = img;
                    newimages[i].src = img.src;
                }
            }
        }
    
        var animateSlideshow = function(current) {
            // this could be used instead of self. I was doing
            // something else at first, but making this copy
            // of the context (this) is not necessary with this
            // code. It doesn't hurt either.
            var self = this;
    
            // Our current context is the containing div, so
            // this.id/self.id will give us the key to the correct
            // group in imgs.sets, and the current argument will
            // tell us with image in that list we're currently
            // working with. First, we hide the last displayed
            // image.
            imgs.sets[self.id][current].style.display = 'none';
    
            // Increment to get the next image.
            current++;
    
            // If we're at the end, let's move back to the
            // beginning of the list.
            if (current >= imgs.sets[self.id].length) {
                current = 0;
            }
    
            // This skips images which had an error on load. The
            // test for this in the markup above is the third image
            // in rotator1, which is not an image url.
            if (imgs.sets[self.id][current].imageerror == true) {
                // See how I'm passing self using .call()? This sets
                // the context for the next animateSlideshow() call,
                // which allows this/self to work on the correct div
                // container.
                animateSlideshow.call(self, current);
                return;
            }
    
            imgs.sets[self.id][current].style.display = 'inline';
    
            // Everything is organized by the self.id key, event
            // saving the references to the timeouts.
            timeouts[self.id] = setTimeout(function(){
                animateSlideshow.call(self, current);
            }, 100);
        };
    
    
        function getImages(){
            var list = document.images,
                img,
                data = {sets: {}, allimages: []},
                parent;
    
            // document.images gives me an array of references to all
            // img elements on the page. Let's loop through and create
            // an array of the relevant img elements, keying/grouping on the
            // parent element's id attribute.
            for (var i = 0, l = list.length; i < l; i++){
                img = list[i];
                parent = img.parentNode;
    
                // parent should now be a reference to the containing div
                // for the current img element. parent.id should give us
                // rotator1 or rotator2 in the demo markup.
                if (parent.className.indexOf('rotation') !== -1) {
                    if (!data.sets[parent.id]) {
                        data.sets[parent.id] = [];
                    }
    
                    // Let's put the img reference into the appropriate
                    // imgs.sets. I also put the img.src into an index
                    // container in data.allimages; this is also a remnant
                    // of a previous approach I took. It could probably be
                    // removed unless you need it.
                    data.sets[parent.id].push(img);
                    data.allimages.push(img.src);
                }
            }
    
            return data;
        }
    
        function initializeSlideshows(){
            imgs = getImages();
    
            preloadImages(imgs.sets);
        }
    
        initializeSlideshows();
    };
    
    $.onDomReady(slideshows);
    

    http://jsfiddle.net/DLz92/1