【Rails6+jQuery】ページの最上部に戻るボタンの実装

### 1.背景
サイトを閲覧する際に目にする「PAGE TOP」などの`戻るボタン`。
今回、Railsで制作したアプリに戻るボタンを実装したので備忘録としてまとめます。

### 2.環境
- mac.os バージョン10.15.6
- Ruby 2.7.2
- Rails 6.1.3.1
- psql (PostgreSQL) 12.6

### 3.手順
#### ①jQueryの導入
今回はyarnを用いてjQueryの導入を行いました。

```ターミナル.
yarn add jquery
```
※yarnとは:JavaCcriptのパッケージマネージャのこと。

#### ②environment.jsを編集

`config/webpack/environment.js`を編集します。

```js
const { environment } = require('@rails/webpacker')

const webpack = require('webpack')
environment.plugins.append('Provide', new webpack.ProvidePlugin({
　    // ここから編集
    $: 'jquery/src/jquery',
    jQuery: 'jquery/src/jquery'
}))

module.exports = environment
```
#### ③application.jsを編集

`app/javascript/packs/application.js`を編集します。

```js
// コード省略
// 下記を追記
require ('jquery')
```
#### ④jQueryを記述したいファイルの作成
今回は、application.jsと同じ階層にcustom.jsというファイル名で作成しました。
`app/javascript/packs/custom.js`

そして、application.jsに記述します。

```js
// コード省略
require ('jquery')
// 下記を追記
require('custom.js')
```

#### ⑤挙動の確認
`app/javascript/packs/custom.js`にテストコードを書き、OKと表示されるか確認します。

```js
$(function() {
  console.log("OK");
});
```
`rails s`でアプリを起動して検証の画面からconsoleタブを選択しました。
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/689555/bb21d17c-235c-81a2-b5a3-38e7ccd70c4b.png" width="80%">

####⑥ボタンの実装(HTML/CSS)
今回はfontawesomeを使用し、下記のようなボタンを実装します。
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/689555/78aa7703-c9dc-f3bc-b096-a177eae85101.png" width=100px>

##### (1) HTML
`app/views/layouts/application.html.erb`の<head>タグ内にfontawesomeを導入するためのコードを記述します。
また、<body>タグ内にボタンを記述します。

```js
// <head>タグ内
<link href="https://use.fontawesome.com/releases/v5.15.3(※バージョンを入れる)/css/all.css" rel="stylesheet">

// <body>タグ内
<div id="page_top"><a href="#"></a></div>
```

##### (2) CSS(scss)
`app/assets/stylesheets/application.scss`にコードを記述します。

```scss
// トップに戻るボタン
#page_top{
  width: 50px;
  height: 50px;
  position: fixed;
  right: 20px;
  bottom: 30px;
  background: #3f98ef;
  opacity: 0.6;
  border-radius: 50%;
}
#page_top a{
  position: relative;
  display: block;
  width: 50px;
  height: 50px;
  text-decoration: none;
  text-align: center;
}
#page_top a::before{
  font-family: "Font Awesome 5 Free";
  content: '\f106';
  font-weight: 900;
  font-size: 25px;
  color: #fff;
  position: absolute;
  width: 25px;
  height: 25px;
  top: 10px;
  bottom: 25px;
  right: 0;
  left: 0;
  margin: auto;
}
```
#### ⑦ボタンの実装(jQuery) 
##### (1) 非推奨の書き方をした→修正
`app/javascript/packs/custom.js`にコードを記述します。

```js
$(function(){
  var pagetop = $('#page_top');
  // ボタン非表示
  pagetop.hide();
  // 100px スクロールしたらボタン表示
  $(window).scroll(function () {
     if ($(this).scrollTop() > 100) {
          pagetop.fadeIn();
     } else {
          pagetop.fadeOut();
     }
  });
  pagetop.click(function () {
     $('body, html').animate({ scrollTop: 0 }, 500);
     return false;
  });
});
```
しかし、[こちら](https://agohack.com/page-top-button-css-jquery/)のように書いたところ、scrollとclickに打ち消し線が入っていました。
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/689555/30dd6bfd-d50d-ea9f-f714-15d8a9e0843f.png" width=70%>

調べたところ、非推奨だと打ち消し線が入るとのことだったので`on()`を使った書き方に変更しました。

```js
$(function(){
  var pagetop = $('#page_top');
  // ボタン非表示
  pagetop.hide();
  // scrollをon('scroll')に変更
  $(window).on('scroll', function () {
     if ($(this).scrollTop() > 100) {
          pagetop.fadeIn();
     } else {
          pagetop.fadeOut();
     }
  });
　　　　// clickをon('click')に変更
  pagetop.on('click', function () {
     $('body, html').animate({ scrollTop: 0 }, 500);
     return false;
  });
});
```
##### (2) 実装したはずが最初の1回しか実装できていない→修正
今回やりたかったのが、
:one: 最初はボタンを非表示
:two: （100px）スクロールしたらボタンが表示される
:three: ボタンを押すと最上部に戻る
...でしたが、アプリを起動した最初の1回だけ思い通りの実装になり、
その後は他のページでもトップページ（アプリを起動した際に最初に表示されるページ）でも
ボタンが表示されたままで、「jQueryが効いていないな・・・？:sweat:」と思うことがありました。

原因を調べると、Turbolinksの影響があることがわかりました。
※Turbolinksとは：Rails4から標準装備されている、ページの遷移を高速化する仕組みのこと。
全てのリンククリックに対するページ遷移を自動的にAjax化（Webブラウザ上で非同期通信を行い、ページの再読み込みなしにページを更新）することで高速化を図る。

Turbolinksはa要素のクリックイベントをフックして、遷移先のページをAjaxで取得します。そして取得したページが要求するJavaScriptやCSSが現在のものと同一であれば現在のものをそのまま使用し、titleやbody要素のみを置き換えます。（→ページ遷移は発生しない。JavaScriptやCSSをブラウザが評価しないので高速化ができる。）

今回の戻るボタンは`<a href="#"></a>`とaタグを使用しました。なのでボタンを押すとTurbolinksの仕組みが動きます。その影響で、
jQueryのコードの処理が実行されないという現象が起きていました。
（[こちら](https://techtechmedia.com/turbolinks-rails/)の`jQueryのreadyイベントが発火しない`に該当します。）

```js
$(document).ready(function(){
  // 処理内容
});

// (document).readyは省略も可能
$(function(){
  // 処理内容 
});
```
最初だけjQueryが動作しているように見えたのは、戻るボタン(=aタグ)を押す前で
Turbolinksが動いていなかったためだと考えられます。

今回は`turbolinks:load`というオプションを使用することで正常な読み込みができるようになりました。

```js
// turbolinks:loadを追記+(document).onという書き方に変更
$(document).on('turbolinks:load', function () {
  var pagetop = $('#page_top');
  // ボタン非表示
  pagetop.hide();
  // 100px スクロールしたらボタン表示
  $(window).on('scroll', function () {
    if ($(this).scrollTop() > 100) {
      pagetop.fadeIn();
    } else {
      pagetop.fadeOut();
    }
  });
  pagetop.on('click', function () {
    $('body, html').animate({ scrollTop: 0 }, 500);
    return false;
  });
});
```
### 4.まとめ
今回色々なサイトを参考に実装しましたが、使用言語のバージョンを踏まえた実装を行うことが大切だと思いました。

### 5.参考
1.[【Rails6】Webpackerを用いてjQueryをインストールする手順を簡単にまとめてみた](https://techtechmedia.com/jquery-webpacker-rails/)
2.[Rails 6: Webpacker+Yarn+Sprocketsを十分理解してJavaScriptを書く: 前編（翻訳）](https://techracho.bpsinc.jp/hachi8833/2021_05_13/85940)
3.[[jQuery] トップへ戻るボタンの実装サンプル](https://agohack.com/page-top-button-css-jquery/)
4.[【jQuery入門】on()によるイベント処理の使い方まとめ！](https://www.sejuku.net/blog/38774)
5.[jQueryでクリックイベントで処理を実行する：on(), click()](https://uxmilk.jp/10065)
6.[【Rails】初心者向け！画面遷移の高速化を行うTurbolinksについて図を用いて詳しく解説](https://techtechmedia.com/turbolinks-rails/)
7.大場寧子他, 現場で使えるRuby on Rails5速修実践ガイド, マイナビ出版, 2018.

### 6.最後に
記事の感想や意見、ご指摘等あれば伝えていただけるとありがたいです。
読んでいただき、ありがとうございました。