使用相同的动画GIF对多个<img/>标签进行异步播放

时间:2013-05-20 13:46:35

标签: javascript html browser asynchronous animated-gif

我在一个HTML网页上有很多<img>个标签,其中一些标签共享相同的动画GIF文件。 src网址是由JavaScript动态设置的,但是我的代码会重新播放相同的字符,或者跟随字符会立即显示最后一帧。

这个想法:这是一个艺术项目。在输入一些文本后,字符以特殊字体显示,并且一些转换是每个字符字符(一个接一个)完成,我只能通过使用动画GIF来实现。文本被拆分为单个字符,<img>标签的创建方式如下:

<!-- delivered HTML at page load -->
<img src="initial/f.png"> <!-- I used to PNG here to outline -->
<img src="initial/o.png"> <!-- the animation is NOT set a first -->
<img src="initial/o.png">

动画开始时,第一个<img>的网址设为transition/f.gif。只有在完成播放(由时间确定)后才会设置第二张图像等。

<!-- while 2nd animation is running -->
<img src="transition/f.gif"> <!-- already finished, displays last frame -->
<img src="transition/o.gif"> <!-- being animated right now -->
<img src="transition/o.png"> <!-- will be reset to o.gif in next step -->

我无法解决的问题:从示例中播放o.gif之后,下一个O的动画无效。

我尝试为每个角色定义一个类,并将图像指定为background-image。一旦出现任何字符,任何后续出现的同一个字母在显示时立即显示该GIF的最后一帧(结束状态)。

我还尝试直接使用JavaScript设置src属性,但是当第二个字母O设置为这样时,第一个字母O的动画会同步重新启动。但它应该停留在最后一帧。

由于HTML页面也应该在本地文件系统上工作,我认为绕过缓存机制的o.gif?random=argument这样的参数将不起作用或者不会产生任何影响(可能在某些计算机上,我自己测试' t falsify)。

2 个答案:

答案 0 :(得分:2)

您必须为图像创建唯一的网址,因此浏览器将始终重新加载字母而不是使用缓存的字母。 你可以用一个小的php来实现这个目的,它为参数输出正确的gif。

<img src="gif_printer.php?letter=o&t=1234567">

t参数应该是创建img标记时的时间戳。这为重新下载提供了足够的差异。

在php set标题中限制/禁用缓存和输出类型为gif,并简单地将图像的内容倒入stdout。

时间戳参数和缓存控制标题应足以让浏览器重新下载外翻字母。

如果您的测试环境没有做出正确的反应,您可以尝试使用htaccess解决方案,但为此您必须使用Web服务器(这可能已足以使之前的解决方案正常工作)。

这意味着将图像/ [a-z] .gif的任何网址重写为images / [a-z] .gif,所以只需删除除第一个字母和扩展名之外的其他噪音。

答案 1 :(得分:2)

考虑不使用GIF,而是使用图像序列和Javascript。我把一个粗略的可实例化的Javascript对象放在一起就是这样:

<html>
    <head>
        <script>
            function Animator(target, frames, delay)
            {
                var _this = this;
                // array of frames (image objects)
                var f = [];
                // a reference to the object where our frames will appear
                var t = document.getElementById(target);
                // the interval variable.  Used to stop and start
                var t_loop;
                // create a new image element and remember it
                var img_el = document.createElement("img");
                // current frame
                var c_frame = 0;

                t.innerHTML = "";
                t.appendChild(img_el);

                var i, img;

                // preload immediately
                for(i = 0; i < frames.length; i++)
                {
                    img = new Image();
                    img.src = frames[i];
                    f.push(img);
                }

                this.play = function()
                {
                    t_loop = window.setInterval(_this.frame, delay);
                }

                this.stop = function()
                {
                    clearInterval(t_loop);
                }

                this.gotoFrame = function(frame)
                {
                    c_frame = frame;
                    _this.frame();
                }

                this.frame = function()
                {
                    img_el.src = f[c_frame].src;

                    c_frame++;

                    if(c_frame >= f.length)
                    {
                        c_frame = 0;
                    }
                }
            }

            function loaded()
            {
                var quip_frames = [
                    "http://www.abcteach.com/images/abma_thumb.gif",
                    "http://www.abcteach.com/images/abcu_thumb.gif",
                    "http://www.abcteach.com/images/zbma_thumb.gif",
                    "http://www.abcteach.com/images/zbcu_thumb.gif",
                    "http://www.abcteach.com/images/dnma_thumb.gif",
                    "http://www.abcteach.com/images/dncu_thumb.gif"
                ];

                var anim1 = new Animator("target1", quip_frames, 100);

                var anim2 = new Animator("target2", quip_frames, 100);

                var anim3 = new Animator("target3", quip_frames, 100);

                anim1.play();
                window.setTimeout(anim2.play, 200);
                window.setTimeout(anim3.play, 300);
            }
        </script>
    </head>
    <body onload="loaded()">
        <div id="target1">
        </div>
        <div id="target2">
        </div>
        <div id="target3">
        </div>
    </body>
</html>

感谢ABCTeach的图片

对象将图像加载到循环中,将它们存储在一个数组中,然后通过简单地使用setInterval()以所需的速率交换帧。当页面加载时,它会生成其中三个对象,每个对象指向不同的DIV,但每个对象都有相同的帧。然后它告诉每个人玩一个不同的延迟(第一个立即,第二个在200ms之后,第三个在300ms之后)。在您的情况下,您将为您使用的每个字母创建一个数组:

var A = [*array of URLs to images of the letter A*];
var B = [*array of URLs to images of the letter B*];    
...

然后为页面上的每个div创建一个新的Animator对象,并向其发送相应的字母数组:

var letter_so_and_so = new Animator("div_so_and_so", A, 100);
var letter_this_and_that = new Animator("div_this_and_that", B, 100);
var another_letter = new Animator("another_div", B, 100);

最后给每个人一个偏移开始,或者调用他们的Animator.gotoFrame(f)方法在不同的帧上启动它们(不要忘记Animator.play()!)。

JSFiddle

尝试在你的代码中采用这样的东西,我认为你会发现它有奇效。