如果图像标签从数据库动态创建,我该如何使用JavaScript或PHP确定图像何时加载完成?

4
我有一个页面,图片很多。这是客户的要求——它是一个商家列表,每个商家都有一个标志。列表很长(超过500个),而且是的,客户坚持要显示所有商家。我们有一个ajax typeahead搜索,可以帮助用户在不滚动的情况下找到他们想要的内容,所以不是完全的灾难。
问题在于:客户现在才意识到由于所有标志,加载此页面需要很长时间。即使每个标志只有几KB,也会很快地累加。他现在决定要显示一个进度条,显示图像正在加载。我以前从未做过这样的事情,所以开始寻找,我看到的大多数进度条都依赖于获取img标记数组并循环检查完成属性。我遇到的问题(至少我认为是这个问题)是,图像标记是由数据库查询生成的,而我认为获取图像数组的javascript是在图像标记完成加载之前加载的。显然,在硬编码图像的页面上不存在这个问题。
有人能指点我如何在动态加载的img标记上实现进度条吗?我的网站是用PHP编写的,所以如果这样更好,我完全可以在服务器端执行某些操作。

关于图像输出的更多细节会更好。格式是什么?可以更改吗?你尝试过哪些JS?能否向我们展示你的源代码等等。 - Petah
9个回答

2
几乎每个人都已经注意到,这是一个难以解决的棘手问题。因此,我建议绕过技术组件,只解决人类方面的问题。
几乎保持一切不变。你所要做的就是找到或创建一个throbber(我使用http://ajaxload.info/,非常容易),并将其用作仅适用于页面上标志的CSS选择器的背景图像。
用户(和提出不合理要求的客户!)更加沮丧的是缺乏响应性,而不是事情花费时间。这个快速的花哨修复可能足以诱导网站用户将问题视为后者而不是前者。

0
这是一个仅使用JavaScript的解决方案,不需要对您的服务器端代码进行任何修改。使用jQuery:
$(document).ready(function() {
    var loadedSoFar = 0;
    //use jquery to get all image tags you want.
    //The totalImgs is used to calculate percent and is the length of the jquery array
    var totalImgs = $("#imgHolder img").each(function(i, img) {
        //if this image has already loaded, add it to loadedSoFar.
        if (img.complete)
            loadedSoFar++;
        else {
            //otherwise add a load event for the image.
            $(img).load(function() {
                loadedSoFar++;
                console.log("complete: " + (loadedSoFar / totalImgs * 100) + "%");
            });
        }
    }).length;
});

我写这篇文章的时候假设所有的图片在文档准备就绪时已经在DOM中了。如果不是这样,请将其移动到一个函数中,并在从服务器加载img标签(例如通过ajax请求)后调用它。

基本上,它只是在imgHolder中查找所有的img(修改选择器以匹配您的情况),并连接load事件,以便可以更新loadedSoFar计数器。如果图像在此脚本运行时已经加载,则永远不会触发load事件,因此立即增加loadedSoFar计数器。需要加载的总图像数量将是选择器返回的jquery对象数组的长度。

我会让你自己编写进度条,但我建议使用这个插件:http://t.wits.sg/jquery-progress-bar/


0

我还没有测试过,但是类似这样的代码可能会起作用(使用jQuery)

<?php // Do your select image stuff from here ?>
<html>
<head></head>
<body>
<script type="text/javascript">
$(document).ready(function () {
    var images = <?php echo json_encode($images); ?>;
    $.each(images, function(i, image) {
        $(new Image()).load(function () {
            $('body').append(this);
            alert('Loaded '+i+' out of '+images.length);
        }).attr('src', image);
    })
});
</script>

同精灵的答案一样。我们不知道任何时候图像会是什么样子,那么我们怎么能像你展示的那样硬编码它们到一个数组中呢? - EmmyS
@EmmyS 嗯,你可能需要更详细地解释一下如何获取你的图像。你是如何存储它们的?你是如何选择它们的?它们是什么格式的?如果它们是存储在数据库中的文件名,只需将它们回显到脚本中(请参见更新的帖子)。或者你可以通过Ajax请求列表。或者其他任何方式。 - Petah
这是一个Joomla网站,因此图像存储在资产目录中,并且它们的路径存储在各个商家的数据库记录中。我从未使用过jquery,并且对ajax不是非常熟悉。json_encode需要返回什么格式?即如果我的查询是select img_path from merchants,那么我需要通过json返回什么才能正确设置images变量?我只需采取查询返回的数组吗? - EmmyS

0

如果我能看到完整的代码,回答这个问题会容易得多,但我记得曾经做过类似的事情,最终使用了一个自定义的JavaScript对象。你可以在应用程序的头部开始使用像这样的一个对象:

function Iterator() {

  var counter = 0;  
  this.images = 215; // This number comes from the DB and gives you a total number of images
  this.progress = counter / this.images

  this.hasMore = function() { counter < this.images }

  this.getPicture = function() {
    // send a request to the server using counter as a parameter
    // upon receiving this request the server should load only ONE image (LIMIT=1 in SQL)
    // with OFFSET equal to the value of "counter"
    // when the image loads (use whatever JS framework you need for that), 
    // we increment the counter:
    counter++;
  }

  this.loadPictures = function() {
    while this.hasMore() {
      this.getPicture()
      // You can do something with the "progress" attribute here, to be visualizad by your progress bar
    }
  }

);

你需要在页面加载时实例化迭代器对象,并让它执行“loadPictures”函数。

如果你在实现过程中遇到任何问题,请告诉我。


0

有不同的方法可以加快图像加载速度,特别是当你有很多图像时

  • 使用雪碧图 - 将多个图像组合在一起,并使用CSS背景属性(事实:一个大图像比多个请求的图像加载速度更快)。
  • 正确使用<image/>标签。您可以添加lowsrc=""属性,以显示低分辨率图像,直到完全加载真实图像,即src=""属性
  • 使用Ajax,尽管您可能有500多张图像,用户永远不会看到完整的列表。因此,您可以在文档完全加载时每次加载6张图像(或N张图像),然后在他们点击“下一页”时添加剩余的图像(这样可以加快加载时间),用户只能看到一些图像,而当他们点击“下一页”或向下滚动时,之前的图像将已经加载好了(或等待时间更短)。更好的做法是,为了节省宽带,只有在需要时才使用Ajax,即仅当用户点击“下一页”或自动滚动到底部时才加载新图像。(看看谷歌图片和滚动时使用的Ajax)

0

既然您已经有一个javascript搜索功能可以让人们更快地找到特定的列表,那么怎么样加载占位符静态图像来代替所有的logo,然后按需替换正确的logo呢?"按需"可以通过JavasScript计算窗口位置和任何输入确定。

从多个子域掩码进行即时图像加载以并行请求,您应该能够在需要时快速弹出图像,而不会通过加载不必要的图像拖慢页面。

这不是很漂亮,但客户的要求也不是很漂亮。

编辑:至于进度条,当您确定窗口位置(或者键入的输入位置)时,确定视图中将有多少列表,并缓冲在视图上下方的多少个列表,然后您将获得总列表数,并且在动态替换该范围内的logo时,您可以更新JavaScript / HTML进度条。


0

我肯定会尽量避免使用进度条 - 这将会让你非常困难。

如果你真的必须这样做,那么最好的方法可能是伪造它 - 即在给定的时间内显示进度,你可以将其设置为加载页面所需的实际时间的近似值。虽然不是万无一失,但比试图实际计时加载进度要容易得多。

还要记住,进度条本身会增加加载时间。而且你需要将其代码嵌入到你的HTML代码中;如果它在外部javascript文件中,它本身可能会受到加载延迟的影响,这将使整个练习毫无意义。

所以,正如我所说,这可能不值得努力。值得努力的是尝试减少加载时间。如果你正在考虑使用进度条,那么显然有些严重问题。

有很多技术可以加快网站加载速度;这是一个独立的主题。但我会给你一些指针。我建议你也花些时间搜索其他和后续信息。

  • 图片优化。如果您还没有这样做,请通过优化程序处理所有图像。您会发现,您可以显著减小文件大小,并因此减少加载时间。

  • CSS Sprites。缓慢加载时间的主要原因之一是具有过多单独的HTTP请求。由于浏览器一次只能加载一定数量的文件,超过该数量的文件必须等到其他文件完成加载后才能开始加载。 CSS雪碧图通过将多个图像合并为一个文件并使用CSS在每个位置仅显示相关部分来解决此问题。这通常用于相关图像组。

  • Lazy Load. 有一个名为LazyLoad的jQuery插件,它告诉您的页面仅在需要时加载图像。超出可见页面底部的图像被推迟到用户开始滚动页面时再加载。这意味着立即可见的图像首先加载,使整个页面看起来更快地加载。

暂时就这样吧。当然,还有很多其他问题,但我想说的是:优化以消除速度问题,而不是试图拼凑一个临时解决方案。

希望这可以帮到你。


0
CSS Sprites对于你的情况来说肯定是一个不错的开始。如果在一个页面上有500个单独的图像,那么浏览器将不得不启动500个新连接来获取它们,不幸的是,并发连接只有大约20个左右,所以...这不好。

来自css-tricks.com的CSS Sprites


1
谢谢,但我认为那样行不通——正如我所说,图像信息存储在数据库中,而不是硬编码到我们的HTML中。商家会一直被添加和删除到数据库中。我们不能维护一个包含所有图像的单个“图像”文件,因为我们从一天到另一天(甚至从一分钟到另一分钟)都不知道会有多少图像以及它们会是哪些。 - EmmyS
@EmmyS:抱歉误解了你的问题。你可以考虑使用多个子域名来并发加载图片。例如,image1.yourdomain.com、image2.domain.com等等,在这种情况下,你可以同时加载更多的图片。 - Michael Mao

0

我建议预先制作并缓存标志(或其各种状态),因为你自己的直觉是主要瓶颈在于“图像标记是由数据库查询生成的”。这是否有可能?

最好存储几个状态或其他内容,并使用命名方案使其可以获取正确的图像,而不是每次都即时重新生成它们。当然,您需要一个适当的缓存处理机制,这不是易事,但往往情况下,您的直觉正在帮助您朝着正确的方向发展。

如果您能够将其简化为每个标志的几个静态文件,则还可以考虑使用CDN和/或多个子域,就像Michael Mao所建议的那样。


不行,不可能。正如我所说的,商家每天都会被添加和删除到数据库中。我们无法以任何方式缓存图像标签 - 它们总是必须在请求时从数据库中获取,以确保用户获取正确的数据。 - EmmyS

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接