首頁  >  文章  >  web前端  >  JS實現無限劃動的圖片全螢幕瀏覽

JS實現無限劃動的圖片全螢幕瀏覽

巴扎黑
巴扎黑原創
2017-05-27 10:46:181524瀏覽

  無限載入策略

  既然是無限劃動,就不能取得所有圖片同時載入; 因為要有劃動效果,因此目前圖片的左右兩張需要預先載入。 所以可以用三張圖片作為一個窗口,並使用輪換策略來實現一個無限劃動的列表。

<p class="lightbox">
  <p class="container">
    <p class="lightbox-item prev"></p>
    <p class="lightbox-item current"></p>
    <p class="lightbox-item next"></p>
  </p>
</p> 

  其中.lightbox全螢幕佈局, 其中的.lightbox-item包含了上一張、目前、下一張圖片。 每當圖片劃動時我們把下一張變成上一張,當前圖變成上一張, 把原來的上一張作為下一張並預先載入下一張圖片資源。

  注意這裡添加了額外的一層.container並讓它包裝所有圖片。 這樣當我們需要圖片進行整體滑動時,就可以為它做一個動畫。

  佈局樣式

#  我們將.lightbox設為全屏,.prev放到當前屏幕的左邊,而.next放到右邊。

.lightbox, .container .lightbox-item{
    position: fixed;
    left: 0;
    right: 0;
    top: 0;
    background-color: #000;
}
.container{
    position: absolute;
}
.lightbox-item{
    /* 我们用背景图来显示图片 */
    position: absolute;
    background-repeat: no-repeat;
    background-position: center;
    background-size: contain;
}
.lightbox-item.prev{
    left: -100%;
    right: 100%;
}
.lightbox-item.next{
    left: 100%;
    right: -100%;
}

  在某些瀏覽器下(例如某款三星的自帶瀏覽器),它會發現頁面內容其實有頁面的三倍寬。 於是就把頁面變寬使得三張圖都顯示出來。設定overflow可修正此問題:

.lightbox{
    overflow: hidden;
}

  綁定觸控事件

  圖片劃動效果的關鍵在於用戶的觸控事件,因為是全螢幕瀏覽所以可以直接綁定到window上。 但綁定到window上我們便要注意衝突和解綁定的問題,可以.off你註冊的函數, 也可以添加一個命名空間,例如:

$(window)
    .on(&#39;mouseup.lightbox touchend.lightbox&#39;, onTouchEnd)
    .on(&#39;mousemove.lightbox touchmove.lightbox&#39;, onTouchMove)
    .on(&#39;mousedown.lightbox touchstart.lightbox&#39;, onTouchBegin)
$(window)
    .off(&#39;mouseup.lightbox touchend.lightbox&#39;)
    .off(&#39;mousemove.lightbox touchmove.lightbox&#39;)
    .off(&#39;mousedown.lightbox touchstart.lightbox&#39;)

  這裡面有6重點的事件,分別是:

  •   mousedown, mousemove, mouseup: 滑鼠按下,移動和放鬆;

  •   touchbegin, touchmove, touchend: 觸碰按下,移動和離開。

  圖片滑動動畫

  其實圖片隨著手指移動並非動畫,只需在touchmove時更新其位置即可。  

// 起始位置,划动距离
var beginX, translateX;
function onTouchBegin(e){
    beginX = getCursorX(e);
}
function getCursorX(e) {
    // 如果是鼠标事件
    if ([&#39;mousemove&#39;, &#39;mousedown&#39;].indexOf(e.type) > -1) {
        return e.pageX;
    }
    // 如果是触摸事件
    return e.changedTouches[0].pageX;
}
function onTouchMove(e){
    translateX = getCursorX(e) - beginX;
    $(&#39;.container&#39;)
        .attr(&#39;transform:translate3d(&#39; + translateX + &#39;)&#39;);
        .attr(&#39;-webkit-transform:translate3d(&#39; + translateX + &#39;)&#39;);
}

  這裡的-webkit-transform是為了相容於Android UC瀏覽器,其他貌似都OK。 另外要注意translate3d會啟用硬體加速,而translateX則沒有。 因此translateX在普通的Android瀏覽器效能都很差。

  當遇到相容性問題時,真想說天煞的UC。但轉念一想至少不用相容IE6,也不必抱怨太多了。

  判斷滑動目標

  上述程式碼還差一個onTouchEnd,即用戶劃動了一段距離後鬆手將會發生什麼事? 如果劃動距離已經夠大,那麼就繼續動畫滑動到下一張,否則就恢復原來的位置。 同時也需要偵測劃動速度,如果距離很短但速度非常大,也應進行圖片切換。

  我們平時劃動圖片時是否從未考慮過這裡的細節?

  在onTouchBegin中記錄開始時間,在onTouchEnd中即可計算速度。

var beginTime, endTime;
function onTouchBegin(e){
    beginTime = Date.now();
}
function onTouchEnd(e){
    endTime = Date.now();
    animateTo(getTarget());
}

  這裡getTarget()用來計算劃動到的圖片,而animateTo則呼叫一個劃動動畫。  

[程式碼]php程式碼:

function getTarget(){
    // 首先检测划动距离,返回 -1, 0, 1 表示上一张,当前,下一张
    var direction = getDirection(translateX, 0.3 * $(window).width());
    // 如果划动距离检测为0,继续检测速度
    if (direction === 0) {
        var deltaT = Math.max(endTime - beginTime, 1);
        var v = translateX / deltaT;
        direction = getDirection(v, 0.3);
    }
    return [&#39;.prev&#39;, &#39;.current&#39;, &#39;.next&#39;][direction + 1];
}
function getDirection(offset, max) {
    if (offset > max) return -1;
    if (offset < -max) return 1;
    return 0;
}

  劃動結束後的動畫

############################## #####  劃動結束後,我們需要將.container滑動到目標圖片。 為了避免生硬地將目前圖片替換為目標圖片,我們設定transform動畫到目標位置,再悄悄替換。 下面便是animateTo的主要邏輯:######
// 计算划动到的目标图片对应的translateX
var translateX = $(window).width() * (1 - idx);
$(&#39;.container&#39;).animate({
    &#39;transform&#39;: &#39;translate3d(&#39; + translateX + &#39;px, 0px, 0px)&#39;
    &#39;-webkit-transform&#39;: &#39;translate3d(&#39; + translateX + &#39;px, 0px, 0px)&#39;
}, {
    duration: 1000,
    complete: function() {
        // 动画结束后进行图片轮换
        var $wps = $(&#39;.container&#39;).find(&#39;.lightbox-item&#39;);
        var $prev = $wps.filter(&#39;.prev&#39;);
        var $curr = $wps.filter(&#39;.current&#39;);
        var $next = $wps.filter(&#39;.next&#39;);
        if (target === &#39;.prev&#39;) {
            idx--;
            $prev.attr(&#39;class&#39;, &#39;lightbox-item current&#39;);
            $curr.attr(&#39;class&#39;, &#39;lightbox-item next&#39;);
            $next.attr(&#39;class&#39;, &#39;lightbox-item prev&#39;);
            prefetch(&#39;.prev&#39;, idx - 1);
        } else if (target === &#39;.next&#39;) {
            idx++;
            $next.attr(&#39;class&#39;, &#39;lightbox-item current&#39;);
            $curr.attr(&#39;class&#39;, &#39;lightbox-item prev&#39;);
            $prev.attr(&#39;class&#39;, &#39;lightbox-item next&#39;);
            prefetch(&#39;.next&#39;, idx + 1);
        }
        $(.container).css(&#39;transform&#39;, &#39;none&#39;);
        $(.container).css(&#39;-webkit-transform&#39;, &#39;none&#39;);
    }
});
######  還記得嗎?我們在圖片滑動後需要去預先取下一張。如此圖片才能連續地進行劃動。 prefetch的操作便是從伺服器預先取下一張圖片位址,然後替換掉滑動視窗中最舊的那張圖。 其具體實作也和伺服器有關,這裡不再贅述了。 ######

  注意!当动画结束时对.prev,.current,.next进行轮换并重置transform。 如果重置为translate3d(0,0,0)则动画仍会继续,页面就会跳一下。 如果重置为none则会非常平滑,同时别忘了-webkit-transform来兼容更多浏览器。

  TouchBegin 的兼容性

  在Android ICS下如果touchbegin和第一个touchmove中都未调用 preventDefault, 后续的touchmove和touchend就不会被触发。 解决办法当然是在onTouchBegin中进行preventDefault(), 然而这样click事件(点击关闭全屏啊!)就不会被触发了:

function onTouchBegin(e) {
    e.preventDefault();
}

  所以我们需要在onTouchMove中来判断这是否是一个Click,并手动触发它的行为。

function onTouchMove(e){
    if(isClick()) onClick(); 

    function isClick() {
        var deltaT = endTime - beginTime;
        var deltaX = Math.abs(translateX);
        // 时间很短,并且移动距离很小,那么应该是个点击!
        return deltaT < 700 && deltaX < 7;
    }
}

  图片渐进载入

  当网速很慢时,连续划动就可能使得旧的图片显示出来(因为预取请求仍未返回)。 常见的一个实践是:立即使用一个已经载入的图片来作为Placeholder, 当目标图片载入后用它替换掉当前的Placeholder。

function loadImage($img, src){
    // 先设置一个Placeholder
    $img.attr(&#39;src&#39;, 
        &#39;data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==&#39;);
    // 载入图片到临时变量
    var tmp = new Image();
    tmp.onload = function(){
        // 资源载入后,将资源显示到目标的img
        $img.src = src;
    };
    tmp.src = src;
}

  设置背景图与设置src属性一样,均可以使用该策略。浏览器会复用那个资源。

  图片到底提示

  在第一张图片右划和最后一张图片左划时,应当给出提示。 可以做一张带有提示信息的Placeholder:

$lightbox.attr(&#39;style&#39;, &#39;top:0;left:0;right:0;bottom:0;&#39;);
$lightbox.append($(&#39;<p class="alert-nomore">&#39;).html(&#39;没有更多了..&#39;));

  然后让文字居中:

.lightbox-item .alert-nomore{
    position: absolute;
    text-align: center;
    bottom: 50%;
    left: 0;
    right: 0;
    color: #777;
    font-size: 20px;
}

以上是JS實現無限劃動的圖片全螢幕瀏覽的詳細內容。更多資訊請關注PHP中文網其他相關文章!

陳述:
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn