【第4回】ページに動きをつけてみよう【jQuery講座】

jQuery講座

本シリーズは、jQueryの書き方を勉強し、その結果をまとめたものになる。

今回は、いよいよjQueryの本気…の一部をお見せできることだろう。

ページに色々な動きをつけてみようと思う。

そのために必要な、animateというメソッドを主に解説していく。

もちろん、前回までの内容もガンガン使っていくので、分からない部分があれば前回までの内容を参照したり、別途Google先生に聞いたりしながら進めていただきたい。

スポンサーリンク

前回の内容の復習

前回は、JavaScriptで使っていた変数や関数を、jQueryと組み合わせてみた

また、特別な変数として、イベントが起こったタグをセレクタとして持ってくるthisというものと、もう一つはオマケの中で出したが、イベントハンドラ内で使用する、イベントの情報が入ったイベントオブジェクトも紹介した。

両方とも今回使うので、それ何だっけ?という方は復習を忘れずに。

以下がその記事だ。

今回のサンプルページ

では、早速今回のサンプルページを見ていこう。

まずページリンクはこちら

ディレクトリ構造は以下のようになっている。

  • jquery
    • course-04_1.html
    • js
      • jquery-04_1.js
    • css
      • style.css
      • style-04_1.css

さて、今回は二種類のサンプルを用意している。

とはいえ、もう一つは今回の内容を応用してちょっとしたものを作ってみたものだ。

そちらは、今回のオマケでリンクを紹介し、ちょっと実装方法や気を付ける点などを深掘りしてみる。

では、メインのサンプルページを見て欲しい。

またしても3つのブロックがあるが、前回までと中身が少し変わっている

まず一つ目、黄色背景になっている部分をクリックしてみてほしい。

すると、文字がスーッと右に移動するはず。

それをもう一回クリックすると、今度は左にスーッと移動。

以降、クリックするごとに移動を繰り返す。

二つ目、これは前回と似ていて、前回はカーソルを乗せたらその瞬間に色が変わっていた。

しかし、今回はクリックで色が変わり、さらにその変化も少しずつになっていると思う。

で、三つ目もほぼ同じ動きをするのだが、一つだけ違う点がある。

両方で、変化している最中にもう一度クリックしてみてほしい。

二つ目は今している変化が終わってから、次の変化が始まっていると思う。

それに対し、三つ目は変化している途中であっても、そこから次の変化になっている

今回のサンプルは、そんな動き方だ。

サンプルのソースは以下の通り。

style.cssは例によって省略させてもらう。

<!DOCTYPE html>
<html lang="ja">
    <head>
        <meta charset="UTF-8">
        <title>jQuery講座第4回サンプルページ</title>

        <!-- jQuery読み込み -->
        <script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
        <script type="text/javascript" src="https://code.jquery.com/ui/1.12.1/jquery-ui.min.js"></script>

        <!-- 各回ごとのJavaScriptファイル読み込み -->
        <script type="text/javascript" src="./js/jquery-04_1.js"></script>

        <!-- 必要に応じてcssファイル読み込み -->
        <link rel="stylesheet" type="text/css" href="./css/style.css">
        <link rel="stylesheet" type="text/css" href="./css/style-04_1.css">
    </head>
    <body>
        <!-- ヘッダー -->
        <div class="header">
            <h1 id="page-title">jQuery講座第4回サンプルページ</h1>
        </div>

        <!-- メインコンテンツ -->
        <div class="main-contents">
            <div class="contents">
                <p>アニメーション1</p>
                <div class="animation-01-parent">
                    <p class="animation-01">文字の移動</p>
                </div>
            </div>
            <div class="contents animation-02">
                <p>アニメーション2</p>
                <p>クリックで色変更、中断なし</p>
            </div>
            <div class="contents animation-03">
                <p>アニメーション3</p>
                <p>クリックで色変更、中断あり</p>
            </div>
        </div>
    </body>
</html>
$(function(){
    /* 文字移動のアニメーション */
    var isLeft = true;
    $(".animation-01").on("click", function(event){;
        if(isLeft){
            $(this).animate(
                {
                    "left": "85%"
                },
                1500
            );
            isLeft = false;
        }else{
            $(this).animate(
                {
                    "left": "0%"
                },
                1500
            );
            isLeft = true;
        }
    });

    /* 背景色変更のアニメーションその1 */
    var isClicked01 = false;
    $(".animation-02").on("click", function(){
        if(!isClicked01){
            $(this).animate(
                {
                    "color": "white",
                    "background-color": "black"
                },
                1500
            );
            isClicked01 = true;
        }else{
            $(this).animate(
                {
                    "color": "black",
                    "background-color": "white"
                },
                1500
            );
            isClicked01 = false;
        }
    });
    
    /* 背景色変更のアニメーションその2 */
    var isClicked02 = false;
    $(".animation-03").on("click", function(){
        if(!isClicked02){
            $(this)
                .stop(true)
                .animate(
                    {
                        "color": "white",
                        "background-color": "black"
                    },
                    1500
                );
            isClicked02 = true;
        }else{
            $(this)
                .stop(true)
                .animate(
                    {
                        "color": "black",
                        "background-color": "white"
                    },
                    1500
                );
            isClicked02 = false;
        }
    });
});
.contents {
    border: 1px solid black;
    margin-top: 1rem;
    margin-bottom: 1rem;
    padding-left: 1rem;
}

.animation-01-parent {
    width: 90%;
    border: 1px solid black;
    margin-bottom: 1rem;
}

.animation-01 {
    width: 15%;
    text-align: center;
    background-color: yellow;
    position: relative;
    top: 0px;
    left: 0%;
}

では、今回の解説内容に入っていこう。

animateメソッド

今回のメインとなる題材は、このanimateメソッドだ。

その名の通り、アニメーションをつけるためのメソッドになる。

で、この中身を解説…する前に、下準備が必要となる。

下準備

初回、jQueryを使うために、jQueryの内容が書かれたJavaScriptファイルを読み込まなければいけないと書いた。

で、それがあれば動くのだが、実はこのanimateメソッドを十分に使うために、別のファイルも読み込まなければいけない

jQuery UIという拡張ライブラリが存在し、それがないと上手く動かないことが多い。

やり方はjQueryと同じく、ファイルをDLしてくる方法と、Webで公開されているものに直接リンクを貼る方法がある。

今回はjQueryと合わせて直接リンクを貼ろう。

今回のリンクはhttps://code.jquery.com/ui/1.12.1/jquery-ui.min.jsで、やり方はjQueryのファイルの時と同じ。

…なのだが、一つだけ注意点がある。

jQueryのファイル読み込みの文も書かれているはずだが、今回のファイル読み込みは、その下に書かなければいけないということ。

jQuery UIはjQueryの拡張なので、元となるjQueryを読み込んである状態でなければいけないのだ。

例えば、以下であればOKだ。

<!DOCTYPE html>
<html lang="ja">
    <head>
        <!-- 省略 -->
        <!-- jQuery読み込み -->
        <script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
        <script type="text/javascript" src="https://code.jquery.com/ui/1.12.1/jquery-ui.min.js"></script>
        <!-- 省略 -->
    </head>
    <!-- 省略 -->
</html>

これは、一つ目がjQueryファイルで、二つ目が今回のjQuery UIのファイル。

こうすれば、上から順番に処理されるので、先にjQueryファイルを読み込んでくれる。

しかし、以下の形ではNGとなる。

<!DOCTYPE html>
<html lang="ja">
    <head>
        <!-- 省略 -->
        <!-- jQuery読み込み -->
        <script type="text/javascript" src="https://code.jquery.com/ui/1.12.1/jquery-ui.min.js"></script>
        <script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
        <!-- 省略 -->
    </head>
    <!-- 省略 -->
</html>

こうすると、jQuery UIの途中で「jQueryが定義されてないよ」という感じのエラーが出る。

もしそれが出たら、こんなことになってないか確認してみよう。

これで、animateメソッドを使う準備が完了した。

なお、この読み込む順番はjQuery UIに限らず、他のどのライブラリでも同じように注意する必要があることを覚えておこう。

animateメソッドの書き方

では、animateメソッドの書き方を見ていこう。

animate(
    {
        プロパティ: 値,
        プロパティ: 値,
        ...,
        プロパティ: 値
    },
    変化時間
)

一番簡単な形は、引数が二つのもの。

一つ目で、変化先のcssを決める。

ここは、cssメソッドにオブジェクトを渡す時と同じ書き方だ。

これで、元の状態から、ここに書いた状態へアニメーションで変化していく

二つ目は、その変化にかける時間を指定する。

ここにはミリ秒単位で指定することになり、例えば1000を指定すれば1000ミリ秒=1秒かけて変化していく、という形だ。

最もシンプルな書き方はこれだけ。

で、ただセレクタを持ってきて、そのままanimateメソッドを動かすと、ページが表示された瞬間に一回アニメーションが行われるだけ。

それだとつまらないので、前回まで使っていたonメソッドを組み合わせて、イベントハンドラ内でユーザーのアクションに対してアニメーションを行うことが多いだろう。

サンプルも、animateメソッドは全てこの形で書いている。

サンプルにおける一つ目のブロックの処理を見てみよう。

/* 文字移動のアニメーション */
var isLeft = true;
$(".animation-01").on("click", function(event){;
    if(isLeft){
        $(this).animate(
            {
                "left": "85%"
            },
            1500
        );
        isLeft = false;
    }else{
        $(this).animate(
            {
                "left": "0%"
            },
            1500
        );
        isLeft = true;
    }
});

処理の流れとしては非常にシンプル。

まず、最初は文字が左にあるので、あらかじめ変数isLefttrueを入れておく。

で、対象の文字がクリックされたら、イベントハンドラの実行だ。

ここで、今文字が左にある…つまりisLefttrueなら右に動かし、isLeftfalseに。

文字が右にあれば、逆のことをしている、というだけだ。

アニメーションの中断

さて、サンプルで試してもらって分かったと思うが、このアニメーションをしている最中にもう一度アニメーションが発生したらどうなるか

これは、何もしないと最初行われていたアニメーションが最後まで行われ、その後次のアニメーションが開始する。

一つ目は移動している文字をクリックするのが難しいと思うので、二つ目のブロックも同じ形で色を変更している。

/* 背景色変更のアニメーションその1 */
var isClicked01 = false;
$(".animation-02").on("click", function(){
    if(!isClicked01){
        $(this).animate(
            {
                "color": "white",
                "background-color": "black"
            },
            1500
        );
        isClicked01 = true;
    }else{
        $(this).animate(
            {
                "color": "black",
                "background-color": "white"
            },
            1500
        );
        isClicked01 = false;
    }
});

ほぼ上と同じなので、ここの詳細は割愛しよう。

さて、状況によっては例えアニメーションの途中だろうとそれを中断し、次のアニメーションを行いたい場合がある。

それを実現するために、別のstopメソッドを使おう。

stopメソッドは一つだけ、真偽値を受け取るメソッドだ。

ここにtrueを指定すると、今アニメーションの実行中であれば、そのアニメーションを中断させることができる。

それにより、次のアニメーションがすぐに行えるようになるのだ。

サンプルでは三つ目にこれを指定している。

その部分を見てみよう。

/* 背景色変更のアニメーションその2 */
var isClicked02 = false;
$(".animation-03").on("click", function(){
    if(!isClicked02){
        $(this)
            .stop(true)
            .animate(
                {
                    "color": "white",
                    "background-color": "black"
                },
                1500
            );
        isClicked02 = true;
    }else{
        $(this)
            .stop(true)
            .animate(
                {
                    "color": "black",
                    "background-color": "white"
                },
                1500
            );
        isClicked02 = false;
    }
});

これでアニメーションの中断を実現できる。

メソッドチェーン

…さて、stopメソッドを使ったサンプルを見ると、セレクタの後ろにstopメソッドがあり、さらにその後ろにanimateメソッドを指定している

実は、同じセレクタに対して複数のメソッドで処理を行う時、このような書き方をすることができる。

これはメソッドチェーンといって、これまたjQueryではよく使われるものだ。

ちょっと、処理を分解して見てみよう。

まず、最初の$(セレクタ)部分で、操作対象となるタグを取得してくる。

この時は、jQueryオブジェクトと呼ばれるオブジェクトを持ってきていることになる。

それに対し、それぞれのメソッドを呼び出していたのだ。

で、各メソッドの戻り値も、このjQueryオブジェクトになっている

そのため、例えば…

$(".class1")
    .stop(true)
    .animate({...}, 1000);

このように書くことで、処理は以下のようになる。

  1. $(".class1")で、クラス名class1のタグ情報を持ったjQueryオブジェクトを取得する
  2. 1で取得したオブジェクトに対し、stopメソッドを実行する
    ⇒戻り値は1と同じjQueryオブジェクト
  3. 2で戻ってきたjQueryオブジェクトに対し、animateメソッドを実行する
    ⇒ここでも同じjQueryオブジェクトが返ってくるので、後ろにさらに繋げることも可能

こんな感じだ。

もちろん、前回まで見ていたcssメソッドやonメソッドも同じ

ただ、当然ながら値を取得するようなメソッドでは使えない。

あくまで、戻り値が同じjQueryオブジェクトのメソッドには使える、という点には注意だ。

これも今後頻出するので、是非覚えておこう。

animateメソッドの他の引数

ここまででサンプルを使った解説は終わりなのだが、もう少しだけ続く。

上では引数が二つの場合で見ていたが、animateメソッドは他にも引数を受け取ることができる

それらを追加すると以下のような書き方になる。

animate(
    {
        プロパティ: 値,
        プロパティ: 値,
        ...,
        プロパティ: 値
    },
    変化時間,
    イージングの種類,
    アニメーション終了時に実行する関数
)

二つ追加し、4つになった。

前二つは同じなので、追加した部分を見ていこう。

第三引数、イージングの種類というものを指定することができる。

これはアニメーションの変化のしかたを指定するもので、文字列で指定を行う。

指定できるものと、それによってアニメーションがどうなるかは読み込むプラグインによっても変わってくる。

それぞれ何が必要でどうなるかは調べれば出てくると思うので、ここで突っ込むのはやめておこう。

ちなみに、デフォルトではswingというものが指定されており、書かなかった場合はそれが適用される。

第四引数、そのままでアニメーションが完了した際に行われる処理を書くことができる。

ここで別のアニメーションを設定すれば、例えば一往復するような動きも表現できる、という感じだ。

このときは、イベントハンドラと同じように無名関数を渡したり、別の関数名を渡したりしてあげよう。

おわりに

今回は、animateメソッドを紹介した。

動きを表現できるようになるので、ようやく見た目にも分かりやすい変化が現れ始めた。

今行われているアニメーションを中断するstopメソッドも併せて使われることが多い。

また、メソッドチェーンという考え方も、処理が軽くなったり、ソースが簡潔になったりとメリットが多いので、使える時は是非使うようにしよう。

さて、次回からは今回までの内容を使って、色々作ってみることにする。

まずは細かいところから、ボタンを用意して、マウスオーバーしたら様々な変化をつけてみる

今回までの内容に慣れるという意味でも、ちょうどいいだろう。

だんだんと増やしていき、最終的には企業の紹介ページみたいなものまで作れればいいなぁ、と思っている。

もちろん、適宜新しいメソッドも出てくると思うので、それらは随時解説を加えていこう。

2021/2/16追記

次回の内容を更新、Twitterの各ボタンをそれっぽく真似してみた

マウスオーバーと予告していたが、それ以外にも少し処理を実装している。

複雑になってきているので、今回までの内容もしっかり頭に入れつつ進んでいこう。

オマケ:クリック点を追いかける矢印

さて、ここからはオマケだ。

今回までの内容でこんなものも作れるよ、という紹介程度のものだ。

まずはサンプルページを見て欲しい。

四角の領域があり、その中に矢印がある。

で、どこでもいいので、四角の領域内をクリックしてみよう。

すると、矢印が回転し、そのクリックした場所に移動してくると思う。

こんなことが、jQueryだけで簡単にできてしまう…と言えればよかったのだが。

ちょっとした落とし穴もあったので、それも紹介していこう。

と、その前にサンプルソースを貼っておく。

階層は上のと同じで、やはりstyle.cssは省略する。

<!DOCTYPE html>
<html lang="ja">
    <head>
        <meta charset="UTF-8">
        <title>jQuery講座第4回オマケ</title>

        <!-- jQuery読み込み -->
        <script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
        <script type="text/javascript" src="https://code.jquery.com/ui/1.12.1/jquery-ui.min.js"></script>

        <!-- 各回ごとのJavaScriptファイル読み込み -->
        <script type="text/javascript" src="./js/jquery-04_2.js"></script>

        <!-- 必要に応じてcssファイル読み込み -->
        <link rel="stylesheet" type="text/css" href="./css/style.css">
        <link rel="stylesheet" type="text/css" href="./css/style-04_2.css">
    </head>
    <body>
        <!-- ヘッダー -->
        <div class="header">
            <h1 id="page-title">jQuery講座第4回オマケページ</h1>
        </div>

        <!-- メインコンテンツ -->
        <div class="main-contents">
            <p class="arrow">→</p>
        </div>
    </body>
</html>
$(function(){
    /* 矢印領域のサイズ */
    var arrowSize = 24;

    /* 回転にかける時間(ミリ秒) */
    var timeRotate = 500;

    /* 回転させるための下準備 */
    $(".arrow").css({
        "transform": "rotate(0rad)",
        "transition": timeRotate + "ms"
    });

    $(".main-contents").on("click", function(event){
        /* 矢印をクリックされたら何もしない */
        if(event.target.className != "main-contents"){
            return;
        }

        /* 今アニメーションの途中ならストップする */
        $(".arrow").stop(true);

        /* クリックされた座標を取得する */
        var mouseX = event.offsetX;
        var mouseY = event.offsetY;

        /* 矢印の中心座標を取得する */
        var arrowX = $(".arrow").position().left + (arrowSize / 2);
        var arrowY = $(".arrow").position().top + (arrowSize / 2);

        /* 矢印からクリック地点への角度を求める */
        var mouseAngle = Math.atan2(mouseY - arrowY, mouseX - arrowX);

        /* 矢印を回転させる */
        $(".arrow").css("transform", "rotate(" + mouseAngle + "rad)");

        /* 回転を待ってから矢印を移動させる */
        setTimeout(function(){
            $(".arrow").animate(
                {
                    "top": mouseY - (arrowSize / 2),
                    "left": mouseX - (arrowSize / 2)
                },
                500
            );
        }, timeRotate);
    });
});
.main-contents {
    border: 1px solid black;
    width: 500px;
    height: 500px;
    margin-top: 1rem;
    margin-bottom: 1rem;
    position: relative;
}

.arrow {
    width: 24px;
    height: 24px;
    text-align: center;
    vertical-align: middle;
    position: relative;
    left: 238px;
    top: 238px;
    margin: 0;
}

animateメソッドの限界

さて、オマケの内容では二つのアニメーションを組み合わせている。

  • 要素の回転
  • 要素の移動

うち、後半の移動は本編でも解説した通りなので問題はないと思う。

で、回転についてはcssでtransformプロパティにrotate関数を指定することにより、その要素を回転させることができる。

つまり、これをanimateメソッドで指定してあげれば…と思っていたのだが、実はこれは不可能だ。

というのも、animateメソッドはさすがに全てのcssプロパティに対応しているわけではなく、例えば今回のような要素の回転には対応していない

このように、一部animateメソッドでは動かすことのできないプロパティがある、ということを知っておこう。

処理の流れ

では、この内容をどうやって実現しているかを見てみよう。

イベントを登録しているonメソッドより前は、単なる下準備なので省略する。

まずは領域に対してonメソッドでイベントを登録。

今回は、マウスクリックされたら、イベントハンドラを実行するようになっている。

イベントハンドラの中では、最初にクリックされているタグを取得して、矢印の領域(arrowクラス)だったら何もしない。

次に、今現在動いている途中であれば、そのアニメーションをstopメソッドで止めている。

動いていなければ、ここでは何も起きない。

そこから、座標を取得している。

前半はマウスクリックの位置を取得しており、ここでイベントオブジェクトから値を取り出している。

書かれているoffsetXoffsetYが、この領域内でのクリックされた座標が格納されているものになる。

後半では、矢印の座標を取得。

jQueryオブジェクトから、positionメソッドを使うことで、親要素に対するその要素の座標を取得することができる。

厳密には、cssのtopleftプロパティの値だ。

これがオブジェクトとして入っているので、それをまず取り出し。

このままだと矢印の左上の座標が取得できることになり、今回は真ん中にするために矢印領域の大きさを使って微調整した。

ちなみに、このpositionメソッドはメソッドチェーンで後ろに繋げることができない例の一つだ。

これで出発点と到着点の座標が取得できたので、今度はJavaScriptの内容でMath.atan2メソッドを使い角度を算出。

ここでの角度は弧度法で表現されたもので、単位はラジアンになっていることに注意だ。

ここまでで、回転させる角度と移動先の座標が取得できた。

あとはアニメーションで動かしていくだけ…なのだが、前述の通り、回転部分はanimateメソッドを使っていない

下準備のところでtransitionプロパティを設定しており、これによって角度が変わったら一定時間アニメーションで変化するようになっている。

そのため、ここではcssメソッドで角度を変えているだけ

その後、animateメソッドで動かす…のだが、ここでそのまま動かしてしまうと、回転と移動が同時に行われてしまう

そこで、これまたJavaScript側だが、setTimeout関数を使って回転する時間だけ待ち、その後animateメソッドで移動させるようなことをしている。

animateメソッド自体は、上で紹介したものと同じ使い方なので問題ないと思う。

以上で、完成だ。

…ものすごく細かいところを見ると、連続でクリックすると座標がずれるのか、矢印の向きが少しおかしなことになっていたりするが、まあオマケなので許してほしい。

とにかく、簡単にここまで実現できてしまう、というのを見てもらいたかったのだ。

矢印を動物などの画像にすればクリック地点を追いかける動物なんかも作れるので、よかったら試してみてほしい。

コメント

タイトルとURLをコピーしました