【问题标题】:Change background image every minute with transition通过过渡每分钟更改背景图像
【发布时间】:2020-08-12 22:06:44
【问题描述】:

我目前正在开发一个私人仪表板。这个仪表板应该有不断变化的背景图像,每分钟都在变化(如果我让它工作的话,将它切换到一个小时或 20 秒应该没问题)。

为此,我注册了 [Pixabay API][1] 并创建了以下 API 请求

https://pixabay.com/api/?key=[my_key]f&q=nature&image_type=photo&orientation=horizontal&min_width=1920&min_height=1080&page=1&per_page=100

通过该请求,我得到一个包含 100 个元素的数组,每个元素都包含以下信息:

comments: 639
downloads: 785498
favorites: 3020
id: 736885
imageHeight: 1195
imageSize: 186303
imageWidth: 1920
largeImageURL: "https://pixabay.com/get/51e3d34b4257b108f5d0846096293076123ddee2504c704c7c2879d79048c05a_1280.jpg"
likes: 3966
pageURL: "https://pixabay.com/photos/tree-sunset-amazing-beautiful-736885/"
previewHeight: 93
previewURL: "https://cdn.pixabay.com/photo/2015/04/23/22/00/tree-736885_150.jpg"
previewWidth: 150
tags: "tree, sunset, amazing"
type: "photo"
user: "Bessi"
userImageURL: "https://cdn.pixabay.com/user/2019/04/11/22-45-05-994_250x250.jpg"
user_id: 909086
views: 2042402
webformatHeight: 398
webformatURL: "https://pixabay.com/get/51e3d34b4257b10ff3d8992cc62f3f79173fd9e64e507440722d78d39248c7_640.jpg"
webformatWidth: 640

然后我从这100个元素中随机选择一个,将largeImageURL设置为背景,再加上半透明的深色叠加层,以便更好地阅读上面的文字。所有这些都在setInterval 内完成,因此每 x 毫秒发生一次。

这是它的代码:

setInterval(function(){
        $.post('getBackgroundImages.php', {  }, function(data) {
        var imageCollection = JSON.parse(data);
        var imageNumber = Math.floor(Math.random() * 100);
        var imageLink = imageCollection.hits[imageNumber].largeImageURL;
        $('body').css("background","linear-gradient(rgba(0,0,0,.3), rgba(0,0,0,.3)),url('"+imageLink+"')");
    });
},60000);

`getBackgroundImages.php' 只是打印 API 请求的内容。

现在的问题如下:在实施的解决方案中,一切正常,新照片显示为背景和切换工作。但是,背景总是设置为灰色背景大约半秒,然后才显示图像,这看起来确实不太好,尤其是在经常切换图像时。

我想要的是在短时间内切换没有这个灰色背景的背景,即使有过渡也是如此,所以变化不会那么突然......

我找到了一种解决方案,先显示图像的模糊预览,然后再显示全分辨率。但是,我认为这不应该是必需的,因为基本上,图像有足够的时间来加载,并且背景应该在图像加载后发生变化。我不在乎,如果每 62 秒发生一次变化,即使我将其设置为 60 秒,因为需要先加载图像。

谁能给我一个关于如何让这个工作更好的提示?

提前致谢! [1]:https://pixabay.com/api/docs/

【问题讨论】:

  • 也许尝试预热图像缓存作为实际执行转换的先决条件。看看是否这样做:my answer to loading image through promise 获取缓存的实际图像并准备好立即显示,然后然后执行转换。我不知道问题是存在中间灰色背景,还是没有加载图像并且发生“弹出”。你不需要通过画布渲染,你只需要浏览器不需要单独的请求。
  • @zero298get it 与 javascripts promise 的提示一起工作...现在图像更改发生在大约 100 毫秒我会说,所以可以接受... 现在我正试图让过渡发生在那里,所以变化不是那么粗糙
  • 如果您尝试交叉淡入淡出,您可能需要 2 个容器元素。目前还没有一种干净的方法可以在纯 CSS 中对图像背景进行交叉淡入淡出。这就是为什么您可能需要将类似双缓冲区的解决方案与一些信号器混合,以告诉您第二个缓冲区已加载并准备好渲染。然后只是淡化“当前”缓冲区/容器上的不透明度。
  • @zero298 hmmm... 我找到了一个使用 jQuery 的fadeTo 函数的解决方案,执行$('body').fadeTo('slow', 0.3, function() { $(this).css("background","linear-gradient(rgba(0,0,0,.3), rgba(0,0,0,.3)),url('"+images[index]+"')"); }).fadeTo('slow', 1);,但是,然后屏幕上的孔内容消失了,而不是只有背景图像...

标签: javascript html jquery css background-image


【解决方案1】:

也许最简单的方法是在两个像背景一样工作的容器之间交替:

HTML:

<body>
    <div class='bg' id='firstBg'></div>
    <div class='bg' id='secondBg'></div>

    <...Your Stuff...>

</body>

CSS:

body {
    background: transparent;
}

.bg {
    position: fixed;
    left: 0;
    top: 0;
    width: 100vw;
    height: 100vh;
    background-position: center;
    z-index: -1;
    background-size: cover;
    transition: 3s ease-in;
}

#secondBg {
    display: none;
}

JS:

setInterval(function(){
    $.post('getBackgroundImages.php', {  }, function(data) {
        var imageCollection = JSON.parse(data);
        var imageNumber = Math.floor(Math.random() * 100);
        var imageLink = imageCollection.hits[imageNumber].largeImageURL;
        if ($('#firstBg').css('display') == 'none') {
            $('#firstBg').css("background-image","url('"+imageLink+"')");
            $('#firstBg').fadeIn();
            $('#secondBg').fadeOut();
        }
        else {
            $('#secondBg').css("background-image","url('"+imageLink+"')");
            $('#secondBg').fadeIn();
            $('#firstBg').fadeOut(); 
        }
    });
},60000);

【讨论】:

    【解决方案2】:

    感谢@zero298 的提示,我现在做了以下解决方案。

    <script>
    function loadImages (images) {
      // each image will be loaded by this function.
      // it returns a Promise that will resolve once
      // the image has finished loading
      let loader = function (src) {
        return new Promise(function (resolve, reject) {
          let img = new Image();
          img.onload = function () {
            // resolve the promise with our url so it is
            // returned in the result of Promise.all
            resolve(src);
          };
          img.onerror = function (err) {
            reject(err);
          };
          img.src = src;
        });
      };
    
      // create an image loader for each url
      let loaders = [];
      images.forEach(function (image) {
        loaders.push(loader(image));
      });
    
      // Promise.all will return a promise that will resolve once all of of our
      // image loader promises resolve
      return Promise.all(loaders);
    }
    
     function cycleImages (images) {
        let index = 0;
        setInterval(function() {
          // since we need an array of the image names to preload them anyway,
          // just load them via JS instead of class switching so you can cut them
          // out of the CSS and save some space by not being redundant
          $('body').css("background","linear-gradient(rgba(0,0,0,.3), rgba(0,0,0,.3)),url('"+images[index]+"')");
          // increment, roll over to 0 if at length after increment
          index = (index + 1) % images.length;
        }, 28800000);
      }
    
    $(function(){
        $.post('getBackgroundImages.php', {  }, function(data) {
            var imageCollection = JSON.parse(data);
            var imageNumber = Math.floor(Math.random() * 100);
            var imageLink = imageCollection.hits[imageNumber].largeImageURL;
            $('body').css("background","linear-gradient(rgba(0,0,0,.3), rgba(0,0,0,.3)),url('"+imageLink+"')");
        });
        $.ajax('getBackgroundImages.php',{
            success:function(data) {
                var parsed = JSON.parse(data);
                var images = parsed.hits;
                var imageUrls = [];
                images.forEach(function(item,index){
                    imageUrls.push(item.largeImageURL);
                })
                loadImages(imageUrls).then(cycleImages).catch(function (err) {
                    console.error(err);
                });
            }   
        });
    });
    </script>
    

    这首先将所有 imageUrls 放入一个数组中,然后使用 Promise 加载所有图像,然后显示,然后没有很大的延迟。我并没有真正设法在切换图像之间获得一个很好的过渡,因为 jQuery s fade-to 方法让页面的内容也淡出,而不仅仅是背景图片...

    顺便说一句,添加更多的div/改变页面的结构并不容易,因为有很多浮动和其他css规则可以使元素出现在页面的各个位置。在所有内容周围添加一个 div 以尝试为该 div 提供背景图像破坏了孔布局...

    总而言之,我对这个解决方案很有信心,但是,如果有人有让切换更顺畅的好主意,请随时告诉我 :)

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2023-03-12
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-11-17
      相关资源
      最近更新 更多