【第9回】本格的なページを作ってみよう【jQuery講座】

jQuery講座

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

今回は、ついにこれまでの内容を使って、実際に使われているようなページを作っていこうと思う。

ただし、構造が複雑になってくるので、大まかな構造や処理から考えていく。

当然ながらこれまで解説してきた内容は全て前提としているし、なんなら新しい内容が出てくることもあるだろう。

また、jQueryだけでなく、HTMLやCSS、JavaScriptの知識も必要だ。

そのあたり、細かい部分はそれぞれで補足しながら進めていこう。

スポンサーリンク

前回の復習

前回は、画面をスクロールしてもついてくるスティッキーヘッダーを実装した。

これ自体はかなりシンプルに実現でき、そんなに難しくなかったと思う。

一緒に解説したスタイルと処理を切り分けて実装する考え方も重要だったりもするので、覚えておきたい。

また、見た目に影響のない範囲で処理回数を減らすスロットリングという考え方もご紹介した。

そこで出したプラグインも是非使えるようにしておきたい。

以下がその記事だ。

注意事項

さて、作っていく前に三つ注意事項を。

…申し訳ないのだが、ページデザインの部分はまだこれから勉強する

そのため、「ここはこう配置した方が…」とか、「この色なんか変…」とか、色々突っ込みどころがあると思う。

もしその知識をお持ちであれば、是非改変を加えていただきたい。

あくまで、今回の目的はjQueryを使うところにあることを覚えておいて欲しい。

次に、これまでのサンプルもそうだったのだが、PCからの閲覧を前提とし、レスポンシブデザインは考えない

これも理由は同じで、レスポンシブデザインはどちらかというとCSSの内容。

今回のjQueryとは関係ないし、こちらの方が時間がかかりそうなので省略させてもらう。

最後、サンプルを作り終えてから思った事なのだが、一応見た目はそれっぽくなっている。

しかし、CSSが汎用性を持っていない

言い換えると、コンテンツの中身によっては表示が大きく崩れる可能性が高いし、もしページレイアウトを変更しようとしたら大がかりな修正が必要な状態になってしまっている。

で、最初それを直そうとしたのだが…それをやっているとこれまたかなりの時間を要すると判断した。

そのため、もしCSSを参考にしようとしている方がいらっしゃったら、それはやめてほしい。

繰り返しになるが、あくまで今回はjQueryがメインなので、そこだけ気を付けておこう。

サンプルページの要件

では、まずこれを固めていこう。

どんなページを作るか、まずは大まかな方針を決めていく。

今回の方針は、ブログのトップページにしよう。

本来であれば、記事の中身はデータベースに入れておき、PHP等でそのコンテンツを埋め込むことにより実現していく。

しかし、そこまでやるとやはり本講座の範囲を外れてしまうので、今回はダミーコンテンツを用意してそれを直接HTMLに書かせてもらう。

PHPで得た内容をどうするか、という部分に焦点を当てているようなイメージで見てもらえれば幸いだ。

トップページの構造と入れる情報

次に、大まかな構造とそこにどんな情報を入れるかを考えてみる。

構造としては…

  • ヘッダー領域
  • トップコンテンツ領域
  • メインコンテンツ領域
  • サイドコンテンツ領域
  • フッター領域

あたりを用意しよう。

ヘッダーが一番上にあり、そのすぐ下に幾つかそのブログで重要な記事をトップコンテンツとして並べる。

その下にはメインとサイドが横並びで2カラム構成、一番下にフッター、というイメージ。

図にすると以下のような感じを考えている。

作成するページ構成概要

サイズはまだ適当だ。

それぞれの中に入れる情報は以下のような感じだろうか。

  • ヘッダー領域
    • ブログタイトル
    • 各主要ページへのメニュー
  • トップコンテンツ領域
    • 重要記事カード
  • メインコンテンツ領域
    • 最新記事一覧
  • サイドコンテンツ領域
    • プロフィール
    • 人気記事
    • 各月のアーカイブ
  • フッター
    • ブログ概要
    • メニュー
    • ソーシャルメディア
    • コピーライト表示

この入れる情報に関しては幾つかサイトを参考にさせてもらっているが、大体こんな感じだった。

その他、もう一つボタンを用意しようと思う。

ページがスクロールされているとき、ページの一番上へスクロールさせるボタンを画面右下に出現させる。

で、このままでもいいのだが、組みやすさを考えてもう一つ手を加える。

トップ、メイン、サイドの3コンテンツも、一つの大きなコンテンツ領域として考えよう。

つまり、書き直すと以下のような構造になる。

  • ヘッダー領域
  • コンテンツ領域
    • トップコンテンツ領域
    • メインコンテンツ領域
    • サイドコンテンツ領域
  • フッター領域
  • スクロールボタン領域

各要素の動き方

では、書く内容と大まかな位置が決まったので、それぞれのjQueryによる処理を細かく見ていこう。

ヘッダー領域

ここは、ブログタイトルと各主要ページへのリンクを入れる。

この中でもさらに二つの領域に分ける、というイメージ。

トップページなので、最初はブログタイトルは大きく、そのすぐ下にヘッダーメニューの形でリンクを入れていこう。

トップページ部分は特に何も処理は行わない。

メニューはスティッキーヘッダーで実装し、画面に追従していない時は全体を使って、追従しているときは左にブログタイトル、右にメニューを固めて配置するように変化させてみる。

実装方法は、前回のスティッキーヘッダーとほぼ同じで、主にはクラスの付け替えで行う。

しかし、メニュー内のブログタイトルはフェードイン・フェードアウトにしたく、これはjQuery側でfadeIn、fadeOutメソッドを使っていこう。

トップコンテンツ領域

ここは、そのブログで重要な記事へのリンクをそれぞれブログカードとして入れる。

ちょっと、場合分けをして実装してみよう。

ここに入れる記事数が3以下の場合は、単に横並びで配置する。

4以上となったら、表示は3つ単位にして、スライドショーで表示する。

一つのスライドに3つの記事を入れるイメージで、3の倍数でなかったら、最後は1記事や2記事の表示となる。

時間経過で次の内容に切り替わったり、左右のボタンやインジケーターも用意しよう。

時間経過での切り替えはやはりカーソルを重ねた時は無効化し、離れている時のみ動かすようにする。

左右ボタンは1スライドの時は非表示に、2スライド以上で初めて出現する形。

インジケータは1スライドの場合でも、それを示すために常に表示する。

メインコンテンツ領域

ここは最新記事一覧を入れる。

ページングについては通常PHPで実装するので、こちらは単に表示のみだ。

で、サンプルではページングがない状態での実装となっている。

もしあったとしても、変化するのはHTMLとCSSのみだ。

その他も、jQuery側で処理する内容はない。

サイドコンテンツ領域

ここはプロフィールや人気記事等の内容だ。

処理に関わる内容は、ここもないだろう。

もしレスポンシブデザインにするなら、横にサイドメニュー開閉のボタンを用意し、それで表示するというのが良さそうに思う。

フッター領域

最後、ここも幾つか情報を入れるのみ。

特にこれといって処理が必要ではない。

ページ上部への移動ボタン

ここは幾つか処理が必要だ。

まず、ページスクロールによってボタン自体を出し入れする処理

このタイミングは、スティッキーヘッダーの切り替えと合わせよう。

次に、クリックでスクロールを戻す処理

これだけは新しい内容、かつ注意点もあるので、実装のところで解説をしていこう。

サンプルページ

さて、ここまで書いてきた内容を実際に実装してみた。

サンプルページはこちらで、今回はCSSのサンプル掲載は避ける。

というのも、上記の通り、あまり参考にしていただけるような形ではないからだ。

ディレクトリ構造は以下の通り。

  • jquery
    • demo
      • blog
        • index.html
        • js
          • script.js
        • css
          • style.css
        • image
          • (使用する画像)

サンプルにアクセスしてもらうと、なんかそれっぽいページが出てくると思う。

画面をスクロールしたり、スライドをいじってみたりしてみよう。

ソースについて、HTMLとJavaScriptは以下のような感じになっている。

<!DOCTYPE html>
<html lang="ja">
    <head>
        <!-- ページ基本設定 -->
        <meta charset="UTF-8">
        <title>ブログメインタイトル</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>
        <script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/jquery-throttle-debounce/1.1/jquery.ba-throttle-debounce.min.js"></script>

        <!-- 自作JSファイル読み込み -->
        <script type="text/javascript" src="./js/script.js"></script>

        <!-- 自作CSSファイル読み込み -->
        <link rel="stylesheet" type="text/css" href="./css/style.css">

        <!-- ヘッダーメニューアイコン用CSSファイル読み込み -->
        <link rel="stylesheet" type="text/css" href="https://use.fontawesome.com/releases/v5.6.1/css/all.css">
    </head>
    <body>
        <!-- ヘッダー領域 -->
        <div class="header-area">
            <div class="header-blog-title">
                <div class="header-blog-title-text">
                    <p class="blog-sub-title">ブログサブタイトル</p>
                    <p class="blog-title">ブログメインタイトル</p>
                </div>
            </div>
            <div class="header-menu">
                <p class="blog-title">ブログメインタイトル</p>
                <ul>
                    <li>
                        <a href="#">
                            <i class="fas fa-home fa-fw"></i> Top 
                        </a>
                    </li><li>
                        <a href="#">
                            <i class="fas fa-folder fa-fw"></i> Category 
                        </a>
                    </li><li>
                        <a href="#">
                            <i class="fas fa-user fa-fw"></i> Profile 
                        </a>
                    </li><li>
                        <a href="#">
                            <i class="fas fa-envelope fa-fw"></i> Contact 
                        </a>
                    </li>
                </ul>
            </div>
        </div>
        
        <!-- コンテンツ領域 -->
        <div class="contents-area">

            <!-- トップコンテンツ領域 -->
            <div class="top-contents-area">
                <div class="slide-area">
                    <div class="slide-contents">
                        <article class="blog-card-small">
                            <a href="" class="card-eyecatch">
                                <img src="./image/eyecatch-01.jpg">
                            </a>
                            <div class="card-category">
                                <a href="#">
                                    <i class="fas fa-folder fa-fw"></i>カテゴリー1
                                </a>
                            </div>
                            <h2 class="card-title">記事タイトル1</h2>
                            <a href="" class="card-link">続きを読む</a>
                        </article>
                        <article class="blog-card-small">
                            <a href="" class="card-eyecatch">
                                <img src="./image/eyecatch-02.jpg">
                            </a>
                            <div class="card-category">
                                <a href="#">
                                    <i class="fas fa-folder fa-fw"></i>カテゴリー2
                                </a>
                            </div>
                            <h2 class="card-title">記事タイトル2</h2>
                            <a href="" class="card-link">続きを読む</a>
                        </article>
                        <article class="blog-card-small">
                            <a href="" class="card-eyecatch">
                                <img src="./image/eyecatch-03.jpg">
                            </a>
                            <div class="card-category">
                                <a href="#">
                                    <i class="fas fa-folder fa-fw"></i>カテゴリー1
                                </a>
                            </div>
                            <h2 class="card-title">記事タイトル3</h2>
                            <a href="" class="card-link">続きを読む</a>
                        </article>
                        <article class="blog-card-small">
                            <a href="" class="card-eyecatch">
                                <img src="./image/eyecatch-04.jpg">
                            </a>
                            <div class="card-category">
                                <a href="#">
                                    <i class="fas fa-folder fa-fw"></i>カテゴリー3
                                </a>
                            </div>
                            <h2 class="card-title">記事タイトル4</h2>
                            <a href="" class="card-link">続きを読む</a>
                        </article>
                    </div>
                </div>
                <div class="slide-nav">
                    <p class="prev"><i class="fas fa-angle-left"></i></p>
                    <p class="next"><i class="fas fa-angle-right"></i></p>
                </div>
                <div class="slide-indicator">
                </div>
            </div>

            <!-- メインコンテンツ領域 -->
            <div class="main-contents-area">
                <article class="blog-card-big">
                    <h2 class="card-title">記事タイトル1</h2>
                    <div class="card-date"><i class="far fa-calendar-alt"></i>yyyy/mm/dd</div>
                    <div class="card-category">
                        <a href="#">
                            <i class="fas fa-folder fa-fw"></i>カテゴリー1
                        </a>
                    </div>
                    <a href="" class="card-eyecatch">
                        <img src="./image/eyecatch-01.jpg">
                    </a>
                    <div class="card-description">
                        本文1<br>あいうえおかきくけこあいうえおかきくけこあいうえおかきくけこあいうえおかきくけこあいうえおかきくけこあいうえおかきくけこあいうえおかきくけこあいうえおかきくけこあいうえおかきくけこあいうえおかきくけこあいうえおかきくけこあいうえおかきくけこあいうえおかきくけこあいうえおかきくけこあいうえおかきくけこ
                    </div>
                    <div class="card-link">
                        <a href="">続きを読む</a>
                    </div>
                </article>
                <article class="blog-card-big">
                    <h2 class="card-title">記事タイトル2</h2>
                    <div class="card-date"><i class="far fa-calendar-alt"></i>yyyy/mm/dd</div>
                    <div class="card-category">
                        <a href="#">
                            <i class="fas fa-folder fa-fw"></i>カテゴリー2
                        </a>
                    </div>
                    <a href="" class="card-eyecatch">
                        <img src="./image/eyecatch-02.jpg">
                    </a>
                    <div class="card-description">
                        本文2<br>あいうえおかきくけこあいうえおかきくけこあいうえおかきくけこあいうえおかきくけこあいうえおかきくけこあいうえおかきくけこあいうえおかきくけこあいうえおかきくけこあいうえおかきくけこあいうえおかきくけこあいうえおかきくけこあいうえおかきくけこあいうえおかきくけこあいうえおかきくけこあいうえおかきくけこ
                    </div>
                    <div class="card-link">
                        <a href="">続きを読む</a>
                    </div>
                </article>
                <article class="blog-card-big">
                    <h2 class="card-title">記事タイトル3</h2>
                    <div class="card-date"><i class="far fa-calendar-alt"></i>yyyy/mm/dd</div>
                    <div class="card-category">
                        <a href="#">
                            <i class="fas fa-folder fa-fw"></i>カテゴリー1
                        </a>
                    </div>
                    <a href="" class="card-eyecatch">
                        <img src="./image/eyecatch-03.jpg">
                    </a>
                    <div class="card-description">
                        本文3<br>あいうえおかきくけこあいうえおかきくけこあいうえおかきくけこあいうえおかきくけこあいうえおかきくけこあいうえおかきくけこあいうえおかきくけこあいうえおかきくけこあいうえおかきくけこあいうえおかきくけこあいうえおかきくけこあいうえおかきくけこあいうえおかきくけこあいうえおかきくけこあいうえおかきくけこ
                    </div>
                    <div class="card-link">
                        <a href="">続きを読む</a>
                    </div>
                </article>
                <article class="blog-card-big">
                    <h2 class="card-title">記事タイトル4</h2>
                    <div class="card-date"><i class="far fa-calendar-alt"></i>yyyy/mm/dd</div>
                    <div class="card-category">
                        <a href="#">
                            <i class="fas fa-folder fa-fw"></i>カテゴリー3
                        </a>
                    </div>
                    <a href="" class="card-eyecatch">
                        <img src="./image/eyecatch-04.jpg">
                    </a>
                    <div class="card-description">
                        本文4<br>あいうえおかきくけこあいうえおかきくけこあいうえおかきくけこあいうえおかきくけこあいうえおかきくけこあいうえおかきくけこあいうえおかきくけこあいうえおかきくけこあいうえおかきくけこあいうえおかきくけこあいうえおかきくけこあいうえおかきくけこあいうえおかきくけこあいうえおかきくけこあいうえおかきくけこ
                    </div>
                    <div class="card-link">
                        <a href="">続きを読む</a>
                    </div>
                </article>
            </div>

            <!-- サイドコンテンツ領域 -->
            <div class="side-contents-area">
                <div class="profile">
                    <p>プロフィール</p>
                    <div class="icon"><img src="./image/profile-icon.jpg"></div>
                    <div class="name">名前</div>
                    <div class="description">人物紹介</div>
                </div>
                <div class="favorited-contents">
                    <p>人気記事</p>
                    <article>
                        <a href="" class="eyecatch"><img src="./image/eyecatch-01.jpg"></a>
                        <div class="title"><a href="">記事タイトル1</a></div>
                    </article>
                    <article>
                        <a href="" class="eyecatch"><img src="./image/eyecatch-02.jpg"></a>
                        <div class="title"><a href="">記事タイトル2</a></div>
                    </article>
                    <article>
                        <a href="" class="eyecatch"><img src="./image/eyecatch-03.jpg"></a>
                        <div class="title"><a href="">記事タイトル3</a></div>
                    </article>
                    <article>
                        <a href="" class="eyecatch"><img src="./image/eyecatch-04.jpg"></a>
                        <div class="title"><a href="">記事タイトル4</a></div>
                    </article>
                </div>
                <div class="archive">
                    <p>アーカイブ</p>
                    <ul>
                        <li><a href="">2021年2月</a>(1)</li>
                        <li><a href="">2021年1月</a>(2)</li>
                        <li><a href="">2020年12月</a>(0)</li>
                        <li><a href="">2020年11月</a>(1)</li>
                        <li><a href="">2020年10月</a>(0)</li>
                        <li><a href="">2020年9月</a>(0)</li>
                        <li><a href="">2020年8月</a>(0)</li>
                        <li><a href="">2020年7月</a>(0)</li>
                        <li><a href="">2020年6月</a>(0)</li>
                        <li><a href="">2020年5月</a>(0)</li>
                        <li><a href="">2020年4月</a>(0)</li>
                        <li><a href="">2020年3月</a>(0)</li>
                        <li><a href="">2020年2月</a>(0)</li>
                    </ul>
                </div>
            </div>
        </div>

        <!-- フッター領域 -->
        <div class="footer-area">
            <div class="footer-contents">
                <div class="footer-content">
                    <p class="footer-title">About</p>
                    <p class="about-blog">ブログの紹介文</p>
                    <ul class="about-menu">
                        <li><a href=""><i class="fas fa-caret-right"></i>プロフィール詳細</a></li>
                        <li><a href=""><i class="fas fa-caret-right"></i>その他メニュー1</a></li>
                        <li><a href=""><i class="fas fa-caret-right"></i>その他メニュー2</a></li>
                        <li><a href=""><i class="fas fa-caret-right"></i>お問い合わせ</a></li>
                    </ul>
                </div>
                <div class="footer-content">
                    <p class="footer-title">Menu</p>
                    <ul class="footer-menu">
                        <li><a href="">ホームページ</a></li>
                        <li><a href="">最新記事</a></li>
                        <li><a href="">カテゴリー</a></li>
                        <li><a href="">その他メニュー1</a></li>
                        <li><a href="">その他メニュー2</a></li>
                    </ul>
                </div>
                <div class="footer-content">
                    <p class="footer-title">SNS</p>
                    <a class="twitter-timeline" data-height="370" data-theme="dark" href="https://twitter.com/shino_20191228?ref_src=twsrc%5Etfw">Tweets by shino_20191228</a>
                    <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>
                </div>
            </div>
            <div class="footer-copyright"><i class="far fa-copyright"></i> 2021 Author</div>
        </div>

        <!-- トップへのスクロールボタン領域 -->
        <div class="scroll-button-area">
            <i class="fas fa-arrow-up"></i>
        </div>
    </body>
</html>
$(function(){
    /* --- 変数定義パート --- */

    /* ウィンドウ全体を保持するjQueryオブジェクト */
    var $window = $(window);

    /* ヘッダーメニュー部分を保持するjQueryオブジェクト */
    var $headerMenu = $(".header-area .header-menu");

    /* ヘッダーメニュー内の各項目を保持するjQueryオブジェクト */
    var $headerMenuContents = $headerMenu.find("ul li");

    /* トップコンテンツ領域を保持するjQueryオブジェクト */
    var $topContentsArea = $(".top-contents-area");

    /* トップコンテンツ内、スライド表示エリアを保持するjQueryオブジェクト */
    var $slideAreaOfTopContents = $topContentsArea.find(".slide-area");

    /* トップコンテンツ内、スライドコンテンツ全体を保持するjQueryオブジェクト */
    var $slidesOfTopContents = $slideAreaOfTopContents.find(".slide-contents");

    /* トップコンテンツ内、各スライドを保持するjQueryオブジェクト */
    var $blogCardOfTopContents = $slidesOfTopContents.find(".blog-card-small");

    /* トップコンテンツ内、スライドの戻るボタンを保持するjQueryオブジェクト */
    var $buttonSlidePrev = $topContentsArea.find(".slide-nav .prev");

    /* トップコンテンツ内、スライドの進むボタンを保持するjQueryオブジェクト */
    var $buttonSlideNext = $topContentsArea.find(".slide-nav .next");

    /* トップコンテンツ内、インジケータ領域を保持するjQueryオブジェクト */
    var $slideIndicatorArea = $topContentsArea.find(".slide-indicator");

    /* トップコンテンツ内、各インジケータを保持するjQueryオブジェクト */
    var $slideIndicator;

    /* ページトップボタンを保持するjQueryオブジェクト */
    var $buttonforTop = $(".scroll-button-area");

    /* スクロール時に操作する要素を保持するjQueryオブジェクト */
    var $scrollableObject = getScrollableElementObject();

    /* デフォルトのヘッダー位置 */
    var defaultHeaderMenuTop = $headerMenu.offset().top;

    /* ヘッダーメニュー表示切替のミリ秒数 */
    var durationHeaderMenuChange = 500;

    /* ヘッダーメニュー項目のカーソルによる変化のミリ秒数 */
    var durationHeaderMenuCursor = 250;

    /* トップコンテンツ内、コンテンツ数を保持 */
    var numOfSmallBlogCard = $blogCardOfTopContents.length;

    /* トップコンテンツ内、スライド枚数を保持 */
    var numOfTopContentsSlide = Math.floor((numOfSmallBlogCard - 1) / 3) + 1;

    /* トップコンテンツ内、現在選択されているスライドを保持 */
    var nowTopContentsSlide = 0;

    /* トップコンテンツ内、自動で次のスライドに進むミリ秒数 */
    var durationNextSlideTopContnets = 7500;

    /* トップコンテンツ内、自動スライド変化のタイマーID */
    var timerIdOfTopcontents;

    /* ページトップボタンによるスクロールのミリ秒数 */
    var durationScrollForTop = 500;

    /* --- 初期設定パート --- */

    /* トップコンテンツ内、各スライドの位置を設定 */
    for(var i = 0; i < numOfSmallBlogCard; i++){
        $blogCardOfTopContents.eq(i).css("left", (350 * i) + "px");
    }

    /* トップコンテンツ内、インジケータを用意 */
    for(var i = 0; i < numOfTopContentsSlide; i++){
        $slideIndicatorArea.html($slideIndicatorArea.html() + "<span class='indicator-icon'>●<span class='indicator-id'>" + i + "</span></span>");
    }
    $slideIndicator = $slideIndicatorArea.find(".indicator-icon");
    $slideIndicator.eq(nowTopContentsSlide).addClass("selected");

    /* トップコンテンツ内、スライド枚数が1面だけなら、左右ボタンを非表示にする */
    if(numOfTopContentsSlide < 2){
        $buttonSlidePrev.hide();
        $buttonSlideNext.hide();
    }

    /* トップコンテンツ内、自動スライドをスタート */
    startTimerTopContents();

    /* トップへのスクロール、スクロール可能な要素が見つからない場合にボタンを非表示にする */
    if($scrollableObject == null){
        $buttonforTop.css("display", "none");
    }

    /* --- イベント登録パート --- */

    /* ウィンドウに対するスクロールイベント登録 */
    $window.on("scroll", $.throttle(1000 / 15, toggleSticky));

    /* ヘッダーメニュー、カーソルに対するイベント登録 */
    $headerMenuContents.on({
        "mouseover": changeHeaderContentsSelected,
        "mouseout": changeHeaderContentsUnselected
    });

    /* トップコンテンツ、左右ボタンに対するクリックイベント登録 */
    $buttonSlidePrev.on("click", slidePrevContents);
    $buttonSlideNext.on("click", slideNextContents);

    /* トップコンテンツ、インジケータに対するクリックイベント登録 */
    $slideIndicator.on("click", slideClickedContents);

    /* トップコンテンツ、自動スライドの開始、停止のイベント登録 */
    $slideAreaOfTopContents.on({
        "mouseover": stopTimerTopContents,
        "mouseout": startTimerTopContents
    });

    /* ページトップボタンに対するクリックイベント登録 */
    $buttonforTop.on("click", scrollToTop);


    /* --- 関数定義パート */

    /* 現在のスクロール距離によって、スティッキーヘッダーとページトップボタンの処理を行う */
    function toggleSticky(){
        var nowScrollTop = $window.scrollTop();
        if(nowScrollTop > defaultHeaderMenuTop){
            $headerMenu.addClass("sticky");
            $headerMenu
                .find(".blog-title")
                .fadeIn(durationHeaderMenuChange);
            $buttonforTop.addClass("sticky");
        }else{
            $headerMenu.removeClass("sticky");
            $headerMenu
                .find(".blog-title")
                .fadeOut(durationHeaderMenuChange);
            $buttonforTop.removeClass("sticky");
        }
    }

    /* ヘッダーメニューにカーソルが重なった時の処理を行う */
    function changeHeaderContentsSelected(){
        $(this)
            .stop()
            .animate(
                {
                    "background-color": "rgb(100, 100, 100)"
                },
                durationHeaderMenuCursor
            );
    }

    /* ヘッダーメニューからカーソルが離れた時の処理を行う */
    function changeHeaderContentsUnselected(){
        $(this)
            .stop()
            .animate(
                {
                    "background-color": "black"
                },
                durationHeaderMenuCursor
            );
    }

    /* トップコンテンツ内、次のスライド番号を受け取ってスライドさせる処理を行う */
    function slideTopContents(nextSlide){
        $slideIndicator.eq(nowTopContentsSlide).removeClass("selected");
        $slideIndicator.eq(nextSlide).addClass("selected");
        $slidesOfTopContents.css("left", (-1050 * nextSlide) + "px");
        nowTopContentsSlide = nextSlide;
    }

    /* トップコンテンツ内、一つ前のスライドに移動する処理を行う */
    function slidePrevContents(){
        if(numOfTopContentsSlide < 2){
            return;
        }
        var nextSlide = (nowTopContentsSlide + numOfTopContentsSlide - 1) % numOfTopContentsSlide;
        slideTopContents(nextSlide);
    }

    /* トップコンテンツ内、一つ次のスライドに移動する処理を行う */
    function slideNextContents(){
        if(numOfTopContentsSlide < 2){
            return;
        }
        var nextSlide = (nowTopContentsSlide + 1) % numOfTopContentsSlide;
        slideTopContents(nextSlide);
    }

    /* トップコンテンツ内、クリックされたインジケータのスライドに移動する処理を行う */
    function slideClickedContents(){
        var nextSlide = parseInt($(this).find(".indicator-id").text());
        console.log("次のスライド:" + nextSlide);
        slideTopContents(nextSlide);
    }

    /* トップコンテンツ内、タイマースタートの処理を行う */
    function startTimerTopContents(){
        timerIdOfTopcontents = setInterval(slideNextContents, durationNextSlideTopContnets);
    }

    /* トップコンテンツ内、タイマーストップの処理を行う */
    function stopTimerTopContents(){
        clearInterval(timerIdOfTopcontents);
    }

    /* 画面トップへスクロールさせる */
    function scrollToTop(){
        $scrollableObject.animate(
            {
                scrollTop: "0" 
            },
            durationScrollForTop
        );
    }

    /* トップへスクロールする際にそれを調節できる要素を取得 */
    function getScrollableElementObject(){
        var elm = ["html", "body"];
        for(var i = 0; i < elm.length; i++){
            $elm = $(elm[i]);
            if($elm.scrollTop() > 0){
                return $elm;
            }else{
                $elm.scrollTop(1);
                var isScrollable = $elm.scrollTop() > 0;
                $elm.scrollTop(0);
                if(isScrollable){
                    return $elm;
                }
            }
        }
        return null;
    }
});

先に、HTML側で少し補足。

今回、各アイコンを使用するために、Font Awesomeというものを使っている。

これを使うと、よく見るアイコンを楽に挿入することが可能となる。

これもどちらかというとHTMLやCSS側の内容なので、使ってるよという紹介に留めよう。

詳細は、すでに解説されている記事があるので、是非ググってほしい。

jQueryによる処理

さて、では本題のjQueryを見てみよう。

実装している処理を大まかに並べると以下のような感じだ。

上3つについては、基本対象が少し変わったりしているくらいで、これまでの内容が理解できていれば問題ないはず。

ここでもう一回解説するのもくどいと思うので、過去の内容を参照してほしい。

上のそれぞれの項目に、該当する内容へのリンクを貼っておいた。

最後の上部へのスクロールだけちょっと変わったことをしているので、それに関する処理だけ抜き出して見てみよう。

スクロールボタンの処理

この処理に関わる部分だけ、ソースを抜き出してみる。

/* --- 変数定義パート --- */

/* ページトップボタンを保持するjQueryオブジェクト */
var $buttonforTop = $(".scroll-button-area");

/* スクロール時に操作する要素を保持するjQueryオブジェクト */
var $scrollableObject = getScrollableElementObject();

/* ページトップボタンによるスクロールのミリ秒数 */
var durationScrollForTop = 500;


/* --- 初期設定パート --- */

/* トップへのスクロール、スクロール可能な要素が見つからない場合にボタンを非表示にする */
if($scrollableObject == null){
    $buttonforTop.css("display", "none");
}


/* --- イベント登録パート --- */

/* ページトップボタンに対するクリックイベント登録 */
$buttonforTop.on("click", scrollToTop);


/* --- 関数定義パート */

/* 画面トップへスクロールさせる */
function scrollToTop(){
    $scrollableObject.animate(
        {
            scrollTop: "0" 
        },
        durationScrollForTop
    );
}

/* トップへスクロールする際にそれを調節できる要素を取得 */
function getScrollableElementObject(){
    var elm = ["html", "body"];
    for(var i = 0; i < elm.length; i++){
        $elm = $(elm[i]);
        if($elm.scrollTop() > 0){
            return $elm;
        }else{
            $elm.scrollTop(1);
            var isScrollable = $elm.scrollTop() > 0;
            $elm.scrollTop(0);
            if(isScrollable){
                return $elm;
            }
        }
    }
    return null;
}

念のため、スクロールボタンの表示・非表示はこの中には含まれておらず、これはそのボタンをクリックされた時の処理のみが該当する。

スクロールボタンの表示関係は、スティッキーヘッダーと併せて行っているので、そちらを見てみよう。

さて、イベントの部分に注目すると…

  1. ボタンをクリックされたら、以下を実行するイベントを登録
  2. 事前に取得しておいたスクロール領域に対し、一番上へスクロールするアニメーションを実行する

こんな感じで、処理自体はシンプル。

ポイントとなるのは、操作2でどの要素に対してスクロールアニメーションを実行するかの部分だ。

そもそも、HTMLの構造は、全体がhtmlタグで囲まれ、その中にheadタグ、bodyタグがある、という形になっていた。

このうち、htmlタグとbodyタグについて、どちらでページのスクロールを管理しているかが、実はブラウザによって異なるのだ。

例えば、私が普段使っているGoogle Chromeだとhtmlタグ側で管理されている。

で、実際にスクロールさせるときには、そのどちらに対して処理を行うかを判断しなければならない

そのために、今回は一番下の関数を用意し、それでスクロール可能な要素を取得している。

htmlbodyタグそれぞれで、まず元々スクロールされていればそれが管理しているものなのでそのまま返す。

スクロールされていない時、一回スクロールさせるようscrollTopメソッドで動かしてみる。

これによってスクロール量が変化していれば、その対象がスクロールを管理しているのでそれを返す、というようなことをしている。

返す前に、今一回スクロールしてしまっているので、それを元に戻すのも忘れずに。

また、両方とも取得できなければ、今回はボタンによるスクロール不可としてボタン自体を非表示にする。

これで取得できた対象に処理を行うことで、スクロールを実現できる、という寸法だ。

実はプラグインもあるのだが、今回はこちらのほうが早そうだったので実装してしまった。

気になる方はそちらも調べてみよう。

おわりに

今回は、これまでの内容を総動員して、具体的なページを一つ作成してみた。

くどいようだが、今回はjQueryを使うことを目的としているので、それ以外への突っ込みどころはいくらでもあると思う。

そこが気に入らない方は、是非ご自身で色々カスタマイズして欲しい。

…とにかく、これまでの内容でこれだけのものを作り上げることができる。

しかも、ソースもそこまで複雑ではないので、それだけjQueryは強力だということ。

さて、本シリーズはこれにて完結としよう。

基本的な事項はある程度解説したつもりなので、後はそれをどう使うかや、プラグインの検討がほとんどだろう。

そこまで手を出してしまうといつまでも終わらなくなってしまうので、一旦終了という感じだ。

もしかしたら、私が使ってみて良さそうなものがあれば解説するかもしれない。

…ちなみに、次シリーズについての予定を。

まだ構想段階なので本当にやるかは分からないが、WordPressのテーマを自作してみようと思う。

というのも、細かい所を色々カスタマイズしたいなぁとは思っていたのだが、それをするならいっそ1から作った方が面白いのでは?という発想だ。

もちろん、その中にはカスタマイズに使える内容もあるだろう。

まあ、実際に使える形になるまでは相当時間がかかりそうな気はしているが、その作り方も全て解説するつもりだ。

実際に始めたら、ここにもリンクを貼るようにする。

気になる方がいらっしゃったら、今しばらくお待ちいただきたい。

2021/2/27追記

告知通り、新シリーズを開始した。

WordPressテーマ作成シリーズ、その名の通り1からWordPressのテーマを作っていく。

本シリーズの内容もしばらく後になるが出てくる…はずなので、その時は思い出してもらえると嬉しい。

コメント

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