jQueryで十字型スライダーの作り方

# なぜつくろうとしたか
仕事で十字のスライダー(カルーセル)の実装の必要があり、プラグインでは対応できないと感じたのでつくりました。

![a9695c25-a02d-232c-32a1-575aea6badfc.gif](https://qiita-image-store.s3.amazonaws.com/0/142918/3bc61332-ef3b-7f73-a2ca-750c926bf16c.gif)


[デモ](https://html-source.herokuapp.com/cross_slider.html)
(Herokuの無料プランでサーバーを立てているので、初回の接続は時間が掛かります)

# 作り方

## 参考ページ
[jQueryを使ったスライダーの作り方とその仕組み](http://apoc.jp/jquery-slider-howto/)
横方向へのスライダーは、こちらのページを参照してください。
ここから手を加えて、縦方向にも動くようにします。

## ソース

1ファイルでサクッと動作確認するために、html,css,jsをまとめてあります。

ソースはGitHubにもあげてます。

[cross_slider.html](https://github.com/yamakawa00/html/blob/master/public/cross_slider.html)

```cross_slider.html
<!DOCTYPE html>
<html lang="ja">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width">
    <title>slide</title>
    <style>
        .slider .slide-x {
            width: 315px;
            height: 360px;
            float: left;
            margin: 0;
            padding: 0;
        }

        .slider .slide-set {
            position: absolute;
            }

        .slider {
            width: 315px;
            height: 360px;
            overflow: hidden;
            position: relative;
            border: 1px solid #ddd;
            border-bottom: 3px solid #ddd;
            margin: auto;
        }
    </style>
</head>
<body>

<div id="wrap">
    <div class="slider">
        <div class="slide-set">

            <div class="slide-y">
                <div class="slide-x">
                    <h1>slide1-1</h1>
                </div>

                <div class="slide-x">
                    <h1>slide1-2</h1>
                </div>

                <div class="slide-x">
                    <h1>slide1-3</h1>
                </div>
            </div>

            <div class="slide-y">
                <div class="slide-x">
                    <h1>slide2-1</h1>
                </div>

                <div class="slide-x">
                    <h1>slide2-2</h1>
                </div>

                <div class="slide-x">
                    <h1>slide2-3</h1>
                </div>
            </div>

            <div class="slide-y">
                <div class="slide-x">
                    <h1>slide3-1</h1>
                </div>

                <div class="slide-x">
                    <h1>slide3-2</h1>
                </div>

                <div class="slide-x">
                    <h1>slide3-3</h1>
                </div>
            </div>

        </div>
    </div>
</div>

<button class="slider-left">左へ</button>
<button class="slider-right">右へ</button>
<button class="slider-above">上へ</button>
<button class="slider-below">下へ</button>

<script src="https://code.jquery.com/jquery-3.1.1.min.js"></script>
<script type="text/javascript">
    $(function () {
        "use strict";

        var slideNumX = $('.slide-x').length;  // .slide-xの数を取得して代入
        var slideNumY = $('.slide-y').length;  // .slide-yの数を取得して代入
        slideNumX = slideNumX / slideNumY;  // 1行あたりの.slide-xの数を求める
        
        var slideWidth = $('.slide-x').outerWidth(); // .slide-xの幅を取得して代入
        var slideSetWidth = slideWidth * slideNumX; // .slideの幅×数で求めた値を代入
        $('.slide-set').css('width', slideSetWidth); // .slideSetのスタイルシートにwidth: slideSetWidthを指定
        
        var slideHeight = $('.slide-x').outerHeight(); // .slide-yの幅を取得して代入
        var slideSetHeight = slideHeight * slideNumY; // .slide-yの長さ×数で求めた値を代入
        $('.slide-set').css('height', slideSetHeight); // .slideSetのスタイルシートにheight: slideSetHeightを指定

        var slideCurrentX = 0; // 現在地を示す変数X軸
        var slideCurrentY = 0; // 現在地を示す変数Y軸

        // アニメーションを実行する独自関数
        function slidingX() {
            // slideCurrentXが0以下だったら
            if (slideCurrentX < 0) {
                slideCurrentX = slideNumX - 1;
                // 一番左上端か判定
                if (slideCurrentY === 0) {
                    slideCurrentY = slideNumY - 1;
                } else {
                    slideCurrentY--;
                }
                slidingY();

                // slideCurrentXがslideNumXを超えたら
            } else if (slideCurrentX > slideNumX - 1) { // slideCUrrentX >= slideNumXでも可
                slideCurrentX = 0;
                // 一番右下端か判定
                if (slideCurrentY === slideNumY - 1) {
                    slideCurrentY = 0;
                } else {
                    slideCurrentY++;
                }
                slidingY();
            }

            $('.slide-set').stop(false, true).animate({
                left: slideCurrentX * -slideWidth
            }, 500);
        }

        function slidingY() {
            // slideCurrentYが0以下だったら
            if (slideCurrentY < 0) {
                slideCurrentY = slideNumY - 1;
                // 一番左上端か判定
                if (slideCurrentX === 0) {
                    slideCurrentX = slideNumX - 1;
                } else {
                    slideCurrentX--;
                }
                slidingX();

                // slideCurrentYがslideNumYを超えたら
            } else if (slideCurrentY > slideNumY - 1) { // slideCUrrentX >= slideNumでも可
                slideCurrentY = 0;
                // 一番右下端か判定
                if (slideCurrentX === slideNumX - 1) {
                    slideCurrentX = 0;
                } else {
                    slideCurrentX++;
                }
                slidingX();
            }

            $('.slide-set').stop(false, true).animate({
                top: slideCurrentY * -slideHeight
            }, 500);
        };

        // 左へボタンが押されたとき
        $('.slider-left').click(function () {
            slideCurrentX--;
            slidingX();
        });

        // 右へボタンが押されたとき
        $('.slider-right').click(function () {
            slideCurrentX++;
            slidingX();
        });

        // 下へボタンが押されたとき
        $('.slider-below').click(function () {
            slideCurrentY++;
            slidingY();
        });

        // 上へボタンが押されたとき
        $('.slider-above').click(function () {
            slideCurrentY--;
            slidingY();
        });
    }());
</script>
</body>
</html>
```

## 解説

###css
```css
        .slider .slide-x {
            width: 315px;
            height: 360px;
            float: left;
            margin: 0;
            padding: 0;
        }

        .slider .slide-set {
            position: absolute;
            }

        .slider {
            width: 315px;
            height: 360px;
            overflow: hidden;
            position: relative;
            border: 1px solid #ddd;
            border-bottom: 3px solid #ddd;
            margin: auto;
        }
```

cssは`width`,`height`両方をに固定にします。

### html

```html
    <div class="slider">
        <div class="slide-set">

            <div class="slide-y">
                <div class="slide-x">
                    <h1>slide1-1</h1>
                </div>

                <div class="slide-x">
                    <h1>slide1-2</h1>
                </div>

                <div class="slide-x">
                    <h1>slide1-3</h1>
                </div>
            </div>

            <div class="slide-y">
                <div class="slide-x">
                    <h1>slide2-1</h1>
                </div>

                <div class="slide-x">
                    <h1>slide2-2</h1>
                </div>

                <div class="slide-x">
                    <h1>slide2-3</h1>
                </div>
            </div>

            <div class="slide-y">
                <div class="slide-x">
                    <h1>slide3-1</h1>
                </div>

                <div class="slide-x">
                    <h1>slide3-2</h1>
                </div>

                <div class="slide-x">
                    <h1>slide3-3</h1>
                </div>
            </div>

        </div>
    </div>
```

このソースは、3×3の箱を並べてあるイメージです。
`slide-y`で縦軸の制御、`slide-x`で横軸の制御を行っています。

### JavaScript

```js
    $(function () {
        "use strict";

        var slideNumX = $('.slide-x').length;  // .slide-xの数を取得して代入
        var slideNumY = $('.slide-y').length;  // .slide-yの数を取得して代入
        slideNumX = slideNumX / slideNumY;  // 1行あたりの.slide-xの数を求める
        
        var slideWidth = $('.slide-x').outerWidth(); // .slide-xの幅を取得して代入
        var slideSetWidth = slideWidth * slideNumX; // .slideの幅×数で求めた値を代入
        $('.slide-set').css('width', slideSetWidth); // .slideSetのスタイルシートにwidth: slideSetWidthを指定
        
        var slideHeight = $('.slide-x').outerHeight(); // .slide-yの幅を取得して代入
        var slideSetHeight = slideHeight * slideNumY; // .slide-yの長さ×数で求めた値を代入
        $('.slide-set').css('height', slideSetHeight); // .slideSetのスタイルシートにheight: slideSetHeightを指定

        var slideCurrentX = 0; // 現在地を示す変数X軸
        var slideCurrentY = 0; // 現在地を示す変数Y軸
```

参考ソース元の横軸制御に追加して、縦軸の制御するための変数を定義してあげましょう。

```js
        slideNumX = slideNumX / slideNumY;  // 1行あたりの.slide-xの数を求める
```

`slide-x`は縦の箱の数分存在するので、`slide-y`の数で割ってあげて、1行あたりの`slide-x`の数を求めてあげましょう。

```js
        function slidingX() {
            // slideCurrentXが0以下だったら
            if (slideCurrentX < 0) {
                slideCurrentX = slideNumX - 1;
                // 一番左上端か判定
                if (slideCurrentY === 0) {
                    slideCurrentY = slideNumY - 1;
                } else {
                    slideCurrentY--;
                }
                slidingY();

                // slideCurrentXがslideNumXを超えたら
            } else if (slideCurrentX > slideNumX - 1) { // slideCUrrentX >= slideNumXでも可
                slideCurrentX = 0;
                // 一番右下端か判定
                if (slideCurrentY === slideNumY - 1) {
                    slideCurrentY = 0;
                } else {
                    slideCurrentY++;
                }
                slidingY();
            }

            $('.slide-set').stop(false, true).animate({
                left: slideCurrentX * -slideWidth
            }, 500);
        }
```

横軸移動のための`slidingX`関数を定義してあげます。

```js
            // slideCurrentXが0以下だったら
            if (slideCurrentX < 0) {
                slideCurrentX = slideNumX - 1;
                // 一番左上端か判定
                if (slideCurrentY === 0) {
                    slideCurrentY = slideNumY - 1;
                } else {
                    slideCurrentY--;
                }
                slidingY();
```

表示されている箱が一番左上の場合で、「左へ」が押された場合は、一番右下まで移動してあげるよう処理をしてあげます。

```js
                // slideCurrentXがslideNumXを超えたら
            } else if (slideCurrentX > slideNumX - 1) { // slideCUrrentX >= slideNumXでも可
                slideCurrentX = 0;
                // 一番右下端か判定
                if (slideCurrentY === slideNumY - 1) {
                    slideCurrentY = 0;
                } else {
                    slideCurrentY++;
                }
                slidingY();
            }
```

同じように、一番右端が表示されている場合に「右へ」が押された場合は、一番左上まで移動します。

```js
        function slidingY() {
            // slideCurrentYが0以下だったら
            if (slideCurrentY < 0) {
                slideCurrentY = slideNumY - 1;
                // 一番左上端か判定
                if (slideCurrentX === 0) {
                    slideCurrentX = slideNumX - 1;
                } else {
                    slideCurrentX--;
                }
                slidingX();

                // slideCurrentYがslideNumYを超えたら
            } else if (slideCurrentY > slideNumY - 1) { // slideCUrrentX >= slideNumでも可
                slideCurrentY = 0;
                // 一番右下端か判定
                if (slideCurrentX === slideNumX - 1) {
                    slideCurrentX = 0;
                } else {
                    slideCurrentX++;
                }
                slidingX();
            }

            $('.slide-set').stop(false, true).animate({
                top: slideCurrentY * -slideHeight
            }, 500);
        };
```

横軸移動の`slidingX`関数と同様に、縦軸移動の`slidingY`関数を定義していきます。
最初は複雑そうに思えますけど、分解すると簡単です。