前言 在这篇文章中 ,我们学习了如何设置固定数量的动态背景图。接下来,我们在这篇文章的基础上继续增加功能,让动态背景图的数量也不是固定的、图像也不是固定的。
动态的背景图 在这里,我个人想从两个方面解释动态 。
一方面是当前呈现的图片是不断轮转的,这是轮播图的基本定义。
另一方面就是呈现的图片并不是一开始就固定好的,而是在轮播的过程中不断更新的。
第一个方面我们已经实现了,在这里也就不多赘述。接下来我们思考如何实现第二个方面。
更新图库 为了响应速度更快,我个人倾向于将loading期间加载的内容固定下来,主要是为了能够让loading期间有一个基本的轮播图。
然后,在第一张图片轮转消失后,更新第一张图片。这样的话,显示的是第二张图片,而第一张图片已经在你看不见的地方更新掉了。当回到第一张图片的时候,我们发现轮转出来的是一张新的图片。
这样就能够分两个阶段给出一大批背景图片了。
时间计算 还记得上一篇文章吗,我们使用
为了让第一张图片在这个周期之外更新,我们所需要做的,首先就是确定
但是,光有这个命中缓存 。
命中后,加载速度是相当迅猛的。我们不能赌他的枪里没有子弹。所以我们还需要额外设计一个定时器,要让这个
还记得上一篇文章的流程图吗:
graph LR
    A[第一张图片]--25%-->B[第二张图片]--25%-->C[第三张图片]--25%-->D[第四张图片]--25%-->A 
我们主要是额外增加一个逻辑,让图片能够跟着时间有些修改:
graph LR
    subgraph 轮播图
        A[第一张图片]--25%-->B[第二张图片]--25%-->C[第三张图片]--25%-->D[第四张图片]--25%-->A
    end
    subgraph 同步更新
        E[等待2s]-->F[等待25%的动画结束]-->G[更新图片]-->E
    end
    subgraph 计数器
        H[[count = 0]] --> I[count] --> K[count mod 4]
        G --> I
        K -->|=0| A
        K -->|=1| B
        K -->|=2| C
        K -->|=3| D
    end 
当然,除了mod计算,还有满
graph LR
    subgraph 轮播图
        A[第一张图片]--25%-->B[第二张图片]--25%-->C[第三张图片]--25%-->D[第四张图片]--25%-->A
    end
    subgraph 同步更新
        E[等待2s]-->F[等待25%的动画结束]-->G[更新图片]-->E
    end
    subgraph 计数器
        G-->I{count = 4 ?}--yes-->J[count - 4]-->H-->A
        O[[count = 0]] --> I
        H[count = 0]
        L[count = 1] --> B
        M[count = 2] --> C
        N[count = 3] --> D
        I--no-->K[+1]-->|+1| L & M & N
    end 
需要注意的是,在这里更新图片并不是与图片动画同步的。我这边设置的是当图片转过去之后再更改,也就是说,这里还有一个判断当前轮转索引与修改索引之间的关系。
graph LR
    subgraph 轮播图
        A[第一张图片]--25%-->B[第二张图片]--25%-->C[第三张图片]--25%-->D[第四张图片]--25%-->A
    end
    subgraph 同步更新
        E[等待2s]-->F[等待25%的动画结束]-->G[更新图片]-->E
    end
    subgraph 计数器
        I--(count+2)%4-->P[index]--更新即触发-->G
        I{count = 4 ?}--yes-->J[count - 4]-->H-->A
        O[[count = 0]] --> I
        H[count = 0]
        L[count = 1] --> B
        M[count = 2] --> C
        N[count = 3] --> D
        I--no-->K[+1]-->|+1| L & M & N
    end 
修改src属性还是直接将整个img标签替换掉 在这里,主要讨论的就是更新图片过程中,我们是修改src还是直接将整个img标签替换掉。
如果你有一定的经验,你会发现,如果src相同,则会直接命中缓存,不会更新图片。对于我们目前而言似乎确实可以使用,因为我们的背景图片并不会随意修改,而是始终保持链接。 当然,如果你有更多的经验,你会想到,在GET请求中加上一个时间戳,浏览器就会误以为这是一次新的请求,能够保证始终更新图片。
而如果是整个img直接替换掉,浏览器就会开始渲染流程,能够确保本次请求是一定能够被加载的。
当然,每种方法都有自己的优势跟弊端,这就需要各位自行判断了。接下来我将以替换整个img为例进行说明。
代码实现 好了,又到了show me the code环节。
保存位置 我们还是选择source/js/utils.js文件,在我们最开始增加的addBackgroundImageDiv方法的最下面继续增加:
增加代码 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 let  count = 0 , index = 0 ;const  imgUrls = { 'pc' : [  '/race-miku.jpg' , '/masuri-miku.jpg' , '/planet-miku.jpg' , '/4mikus.jpg' , '/84672028_p0.jpg' , '/84932457_p0.png'  ] } document .onreadystatechange  = function  (  if  (document .readyState  === 'complete' ) {     console .log ('done' );     let  imgChangeInterval = null ;     let  imageChangeTimeOut = setTimeout (function  (       console .log ('timeout' );       if  (imgChangeInterval != null ) {         clearInterval (imgChangeInterval);         imgChangeInterval = null ;       }       imgChangeInterval = setInterval (function  (         index = (count + 2 ) % 4          const  imageDivElement = document .getElementById ("image-scroller" ).children [count % 4 ];         let  sampleImg = Math .floor (Math .random () * imgUrls[DEVICES [0 ]].length );         imageDivElement.innerHTML  = "<img"  +           " src='"  + BASE_URL  + DEVICES [0 ] + imgUrls[DEVICES [0 ]][sampleImg] + "'"  +           " style='width: 100%; height: 100%;'"  +           " alt='network broken?' />" ;         console .log (`changed, now is ${count % 4 }  and ${imgUrls[DEVICES[0 ]][sampleImg]} ` )          count = (count + 1 ) % 4 ;       }, 64000  / 4 );       clearTimeout (imageChangeTimeOut);     }, 2000 );   } } 
这些代码能够按照约定更新图片,达到更多图片的轮播效果。虽然本文展示案例的时候只用了
没什么必要的其他东西 同时,在代码中我也留下了三个节点的console.log方法,能够让各位能够感受到浏览器页面加载状态改变为complete的时候、TimeOut被触发的时候、Interval被触发的时候。
如果不出意外的话,complete输出将会很快出现,然后在timeout,接下来每changed输出。
两篇文章的全部代码 如果你是单纯复制本篇文章中的内容,可能并不能运行起来。因为诸如DEVICES、BASE_URL这类变量是上一篇文章中定义的变量。
所以,在这里,我将给出两篇文章的全部代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 (function (   const  onPageLoaded  = (document .dispatchEvent (     new  Event ('page:loaded' , {       bubbles : true      })   );   if  (document .readyState  === 'loading' ) {     document .addEventListener ('readystatechange' , onPageLoaded, { once : true  });     addBackgroundImageDiv ();    } else  {     onPageLoaded ();   }   document .addEventListener ('pjax:success' , onPageLoaded); })(); function  addBackgroundImageDiv  () {        const  opacityMask = document .createElement ("div" );   opacityMask.style .background  = "linear-gradient(#fff, #ffced9, #fff)" ;   opacityMask.style .position  = "fixed" ;   opacityMask.style .top  = "0" ;   opacityMask.style .left  = "0" ;   opacityMask.style .content  = "" ;   opacityMask.style .width  = "100%" ;   opacityMask.style .height  = "100%" ;   opacityMask.style .opacity  = "0.8" ;   opacityMask.style .zIndex  = "-2" ;   const  imageContainer = document .createElement ("div" );   imageContainer.style .position  = "fixed" ;   imageContainer.style .top  = "0" ;   imageContainer.style .left  = "0" ;   imageContainer.style .content  = "" ;   imageContainer.style .width  = "100%" ;   imageContainer.style .height  = "100%" ;   imageContainer.style .zIndex  = "-3" ;   const  imageScroller = document .createElement ("div" );   imageScroller.id  = "image-scroller" ;   imageScroller.style .position  = "fixed" ;   imageScroller.style .top  = "0" ;   imageScroller.style .left  = "0" ;   imageScroller.style .content  = "" ;   imageScroller.style .width  = "400%" ;   imageScroller.style .height  = "100%" ;   imageScroller.style .display  = "flex" ;   imageContainer.style .justifyContent  = "space-around" ;   imageContainer.style .alignContent  = "center" ;   imageContainer.style .alignItems  = "center" ;   imageScroller.style .zIndex  = "-4" ;   document .body .appendChild (opacityMask);   document .body .appendChild (imageContainer);   document .body .appendChild (imageScroller);            const  BASE_URL  = 'http://images.sakebow.cn/bgimage/'    const  DEVICES  = ['pc' ]   const  imgWindowUrl = { 'pc' : [     '/race-miku.jpg' , '/masuri-miku.jpg' , '/planet-miku.jpg' , '/4mikus.jpg'    ] };   for  (const  imgUrlItem of  imgWindowUrl['pc' ]) {     const  imageFrameItemContainer = document .createElement ("div" );     imageFrameItemContainer.style .width  = imageContainer.style .width ;     imageFrameItemContainer.style .height  = "100%" ;     imageFrameItemContainer.innerHTML  = "<img"  +       " src='"  + BASE_URL  + DEVICES [0 ] + imgUrlItem + "'"  +       " style='width: 100%; height: 100%;'"  +       " alt='network broken?' />" ;     imageScroller.appendChild (imageFrameItemContainer);   }               const  imageRollStyle = document .createElement ('style' );      const  EPOCH_TIME  = 64 ;      const  ANIMATION_DEFAULT_SETTINGS  = "s linear infinite running " ;      imageRollStyle.innerHTML  = `@keyframes image-roll {      0%  { left: 0; } 24% { left: 0; } 25% { left: -100%; } 49% { left: -100%; } 50% { left: -200%; }     74% { left: -200%; } 75% { left: -300%; } 99% { left: -300%; } 100%{ left: 0; }   }@keyframes image-translate-child-1 {     0%  { scale: 1; opacity: 0 } 2% { scale: 1; opacity: 1; } 23% { scale: 1.1; } 25%, 100% { scale: 1.1; opacity: 0; }   }#image-scroller>div:nth-child(1) {     animation: ${EPOCH_TIME + ANIMATION_DEFAULT_SETTINGS}  image-translate-child-1;   }@keyframes image-translate-child-2 {     0%, 25%  { scale: 1; opacity: 0 } 27% { scale: 1; opacity: 1; } 48% { scale: 1.1; } 50%, 100% { scale: 1.1; opacity: 0; }   }#image-scroller>div:nth-child(2) {     animation: ${EPOCH_TIME + ANIMATION_DEFAULT_SETTINGS}  image-translate-child-2;   }@keyframes image-translate-child-3 {     0%, 50%  { scale: 1; opacity: 0 } 52% { scale: 1; opacity: 1; } 73% { scale: 1.1; } 75%, 100% { scale: 1.1; opacity: 0; }   }#image-scroller>div:nth-child(3) {     animation: ${EPOCH_TIME + ANIMATION_DEFAULT_SETTINGS}  image-translate-child-3;   }@keyframes image-translate-child-4 {     0%, 75%  { scale: 1; opacity: 0 } 77% { scale: 1; opacity: 1; } 98% { scale: 1.1; } 100% { scale: 1.1; opacity: 0; }   }#image-scroller>div:nth-child(4) {     animation: ${EPOCH_TIME + ANIMATION_DEFAULT_SETTINGS}  image-translate-child-4;   }` ;           document .getElementsByTagName ('head' )[0 ].appendChild (imageRollStyle);   imageScroller.style .animation  = `${EPOCH_TIME + ANIMATION_DEFAULT_SETTINGS}  image-roll` ;            let  count = 0 , index = 0 ;   const  imgUrls = { 'pc' : [     '/race-miku.jpg' , '/masuri-miku.jpg' , '/planet-miku.jpg' , '/4mikus.jpg' , '/84672028_p0.jpg' , '/84932457_p0.png'    ] }   document .onreadystatechange  = function  (     if  (document .readyState  === 'complete' ) {       console .log ('done' );       let  imgChangeInterval = null ;       let  imageChangeTimeOut = setTimeout (function  (         console .log ('timeout' );         if  (imgChangeInterval != null ) {           clearInterval (imgChangeInterval);           imgChangeInterval = null ;         }         imgChangeInterval = setInterval (function  (           index = (count + 2 ) % 4            const  imageDivElement = document .getElementById ("image-scroller" ).children [count % 4 ];           let  sampleImg = Math .floor (Math .random () * imgUrls[DEVICES [0 ]].length );           imageDivElement.innerHTML  = "<img"  +             " src='"  + BASE_URL  + DEVICES [0 ] + imgUrls[DEVICES [0 ]][sampleImg] + "'"  +             " style='width: 100%; height: 100%;'"  +             " alt='network broken?' />" ;           console .log (`changed, now is ${count % 4 }  and ${imgUrls[DEVICES[0 ]][sampleImg]} ` )            count = (count + 1 ) % 4 ;         }, 64000  / 4 );         clearTimeout (imageChangeTimeOut);       }, 2000 );     }   }    } 
到这里,动态修改、动态显示的背景图片就实现了。