ホームページ  >  記事  >  ウェブフロントエンド  >  JSは無制限のスワイプによる写真の全画面閲覧を実現します

JSは無制限のスワイプによる写真の全画面閲覧を実現します

巴扎黑
巴扎黑オリジナル
2017-05-27 10:46:181534ブラウズ

無限ロード戦略

無限スワイプなので、スワイプ効果があるため、すべての画像を同時にロードすることはできません。現在の画像の左と右をロードする必要があります。プリロードされる。 したがって、3 つの画像をウィンドウとして使用し、回転戦略を使用して無限のスワイプ リストを実現できます。

<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%;
}

一部のブラウザ (特定の Samsung 組み込みブラウザなど) では、ページ コンテンツが実際にはページの 3 倍の幅であることがわかります。 したがって、3 つの画像すべてが表示されるようにページが拡張されます。オーバーフローを設定すると、この問題を解決できます。

.lightbox{
    overflow: hidden;
}

タッチ イベントのバインド

画像のスワイプ効果の鍵は、全画面ブラウジングであるため、ユーザーのタッチ イベントに直接バインドできます。窓。 ただし、ウィンドウにバインドするときは、競合とバインドの問題に注意する必要があります。登録した関数を .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: タッチダウン、移動して離れる。

画像スライドアニメーション

実際には、指で移動する画像はアニメーション化されておらず、タッチ移動時に位置が更新されるだけです。

// 起始位置,划动距离
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 ブラウザとの互換性のためのもので、それ以外は問題ないようです。 また、translate3d はハードウェア アクセラレーションを有効にしますが、translateX はハードウェア アクセラレーションを有効にしないことにも注意してください。 したがって、通常の Android ブラウザでの translationX のパフォーマンスは非常に低くなります。

互換性の問題が発生したときは、Tiansha の 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 code:

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をターゲット画像までスライドさせる必要があります。 現在のイメージがターゲット イメージに突然置き換えられることを避けるために、変換アニメーションをターゲットの位置に設定してから、静かに置き換えます。 以下は 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;);
    }
});

スライドした後に次の画像をプリフェッチする必要があることを覚えていますか?このようにして、画像を連続的にスクロールすることができる。 プリフェッチの操作は、サーバーから次の画像アドレスをプリフェッチし、スライディング ウィンドウ内の最も古い画像を置き換えることです。 その具体的な実装はサーバーにも関連するため、ここでは詳しく説明しません。

  注意!当动画结束时对.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 中国語 Web サイトの他の関連記事を参照してください。

声明:
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。