WebDesign Dackel

【初心者向け】jQueryでツールチップのプラグインを自作しよう – Part1

【初心者向け】jQueryでツールチップのプラグインを自作しよう - Part1

Hatena0
Google+0
Pocket0
Feedly0

はじめに

最近のフロントエンドではjQuery離れがささやかれたりしていますが、そんな中僕が通っていた専門学校の生徒(在校生)さんにjQueryを教える機会がありました。 (大したことは教えてあげられませんが…)
また近いうちにそういった機会がありそうなので、その時のための資料として今回記事に残しておこうと思います。

「Part1」と入っているので予想がつきそうですが、全部で3つのステップに分けて少しずつプラグインとして完成させていきたいと思っています。

シリーズ

  1. 【初心者向け】jQueryでツールチップのプラグインを自作しよう – Part1
  2. 【初心者向け】jQueryでツールチップのプラグインを自作しよう – Part2
  3. 【初心者向け】jQueryでツールチップのプラグインを自作しよう – Part3

こんな人に読んでもらいたいです

下記に該当する方が対象となっています。

  • HTML+CSSjQueryがなんとなーく分かる
  • Lightboxなど、何らかのプラグインを使ったことがある
  • プラグインを作る!ってなんだか難しそう…
  • でも、自分で作れたら楽しそう!

最終目標

まずはじめに、Part3まで進めた時に出来る成果物から。
テキストにマウスを乗せるとアニメーション付きでツールチップが表示されるという、シンプルなプラグインを作りたいと思います。

最終的な動作サンプル

動作サンプル

上記のサンプルを、下記の様なコードで動かせるようにしていきます。

$(function(){
  $(".my-tooltip").tooltip({
    direction: "top",
    duration: 300
  });
});

いっちょまえにオプションを渡していて、なんだかプラグインっぽいですね!
最終的なコードはGitHubにあげていますので、先にどんなものが出来るのか確認しておきたい方は下記よりどうぞ。

tsuyoshiwada/sample-jquery-tooltip

今回の目標

「プラグインを自作する」なんて書きましたが、最初はプラグインを作りません。
まず単純に動作するサンプルを作っていき、そこが上手く行ってから機能をまとめて、汎用性を持たせるためにプラグイン化していきたいと思います。

プラグインの仕様を整理

実際のコードを書いていく前に、どんなプラグインにしたいかをまとめたいと思います。

  • 要素のtitle属性をツールチップとして表示する
  • 表示する方向を変えられる
  • さらに、表示する位置の微調整が可能
  • 表示・非表示の際、フェードアニメーションする

「初心者向け」とタイトルに入れてしまったので、もっと機能を絞ろうと思ったのですが、どうせ作るなら実践的な内容でやりたいと思ったので、わりと多機能にしてみました!

【ちょっと寄り道】そもそもプラグインとは何なんすかね?

プラグインを作る前に、プラグインとは何なのかというところを簡単に抑えておきたいと思います。
IT用語辞典さんでは次のような説明になっていました。

プラグインとは、差し込む、差込口などの意味を持つ英単語。ITの分野では、ソフトウェアに機能を追加する小さなプログラムのことを指す場合が多い。
プラグインとは|plug-in – 意味/解説/説明/定義 : IT用語辞典

ここではITの分野となるので、「ソフトウェアに機能を追加する小さなプログラム」の事です。
ある機能をひとまとめにして大本のライブラリを拡張する、ということになるかと思います。

更にjQueryプラグインに限定していうと、jQueryというオブジェクトに対してメソッド(関数)を追加する、というイメージで問題ないかと思います。

必要なファイルを用意

記事の目的はjQueryを学ぶことなので、HTMLCSSについては、あまり深く掘り下げずさら〜っといきたいと思います。

今回スタイルの初期化にはnormalize.cssを使います。
それと、勿論jQueryも使用するのでそれぞれ下記よりダウンロードしておきましょう。

デスクトップなど適当な場所に、下記の様なファイルを用意します。

./
├── css
│   ├── normalize.css # ←ダウンロードしたファイル
│   └── style.css
├── index.html
└── js
    ├── app.js
    └── jquery-1.11.3.min.js # ←ダウンロードしたファイル

HTML

./index.htmlに下記を記載します。

<!DOCTYPE html>
<html>
<head>
  <meta charset="utf-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <title>jQuery自作ツールチップのサンプル</title>
  <link rel="stylesheet" href="./css/normalize.css">
  <link rel="stylesheet" href="./css/style.css">
</head>
<body>
  <div class="container">
    <h1>jQuery自作ツールチップのサンプル</h1>
    <p>
      <a href="#" class="my-tooltip" title="ツールチップです!">マウスを乗せるとツールチップ</a>が表示されます。<br />
      こちらの<a href="#" class="my-tooltip" title="表示されましたか?">リンク</a>テキストも同様です。
    </p>
  </div>

  <script type="text/javascript" src="./js/jquery-1.11.3.min.js"></script>
  <script type="text/javascript" src="./js/app.js"></script>
</body>
</html>

上記のうち、.my-tooltipにマウスを乗せた時、title属性にある内容をツールチップとして表示したいと思います。

CSS

./css/sytle.cssに簡単にスタイルの指定をしていきます。ツールチップのスタイルもここで指定します。

@charset "utf-8";

body,
html {
  color:#444;
  font-size:18px;
  font-family:sans-serif;
}

.container {
  width:700px;
  margin:0 auto;
  padding:30px;
}

/* ツールチップ本体 */
.tooltip {
  position:absolute;
  z-index:9999;
  display:block;
  color:#fff;
  font-size:14px;
  line-height:1.2;
}

/* ツールチップの内容 */
.tooltip__body {
  position:relative;
  top:-15px;
  padding:10px;
  background:#222;
  -webkit-border-radius:3px;
     -moz-border-radius:3px;
      -ms-border-radius:3px;
          border-radius:3px;
  -webkit-box-shadow:0 2px 4px rgba(0, 0, 0, .4);
     -moz-box-shadow:0 2px 4px rgba(0, 0, 0, .4);
      -ms-box-shadow:0 2px 4px rgba(0, 0, 0, .4);
          box-shadow:0 2px 4px rgba(0, 0, 0, .4);
}

/* ツールチップらしく矢印をつける */
.tooltip__body:after {
  content:"";
  position:absolute;
  bottom:-5px;
  left:50%;
  display:block;
  width:0;
  height:0;
  margin-left:-5px;
  border-width:5px 5px 0 5px;
  border-style:solid;
  border-color:#222 transparent transparent transparent;
}

これでベースは出来ましたので、いよいよ次からJavaScriptのコードを書いていきます。

まずはプラグイン無しでツールチップを出してみよう!

./js/app.jsにツールチップを表示するコードを書いていきます。

一行一行解説を加えていくと長くなってしまいそうなので、あとでポイントを解説、その他の箇所はコメントアウトを参照して下さい。

$(function(){

  var $body = $("body");

  // 各 `.my-tooltip` 要素に対して処理をしていきます
  $(".my-tooltip").each(function(){
    var $this = $(this); //何度か使うため、変数にしまっておきます
    var title = $this.attr("title"); //要素の`title`属性を取得

    // ツールチップ本体を生成します
    var $tooltip = $([
      "<span class='tooltip'>",
        "<span class='tooltip__body'>",
          title,
        "</span>",
      "</span>"
    ].join(""));

    // イベントの設定
    $this
      // マウスが乗ったら...
      .on("mouseenter", function(){

        // <body>へツールチップを追加します
        $body.append($tooltip);

        // 要素の表示位置
        var offset = $this.offset();

        // 要素のサイズ
        var size = {
          width: $this.outerWidth(),
          height: $this.outerHeight()
        };

        // ツールチップのサイズ
        var ttSize = {
          width: $tooltip.outerWidth(),
          height: $tooltip.outerHeight()
        };

        // 要素の上に横中央で配置
        $tooltip.css({
          top: offset.top - ttSize.height,
          left: offset.left + size.width / 2 - ttSize.width / 2
        });
      })
      // マウスが離れたら...
      .on("mouseleave", function(){

        // <body>から、ツールチップを削除します
        $tooltip.remove();
      });
  });
});

ここまで書けたら、./index.htmlをブラウザで開いてみてください。
アニメーションはまだ付いていませんが、リンクテキストにマウスを乗せることで下の画像みたいにツールチップが表示されたでしょうか??

アニメーション無しで表示した例

ブラウザのデフォルトで出てくるツールチップを消す

ただこのままだと要素の上にマウスを乗せたとき、ブラウザが標準で持っている機能のせいでツールチップが2つ表示されてしまいます。

ブラウザデフォルトのツールチップが出ちゃってる例

これを防ぐにはtitle属性の中身を空にしてしまうのが簡単です。
先ほどのコードでツールチップを生成している付近に一行だけ追記します。

// ツールチップ本体を生成します
var $tooltip = $([
  "<span class='tooltip'>",
    "<span class='tooltip__body'>",
      title,
    "</span>",
  "</span>"
].join(""));

// デフォルトで表示されるツールチップを消す
$this.attr("title", "");

// イベントの設定
$this

これで、JSで制御している方のツールチップだけが表示されるようになったかと思います。

アニメーションを付ける

これまではパッと表示されるようになっていましたが、簡単なフェードアニメーションをつけていきたいと思います。

ツールチップの初期状態を非表示にしておく

<body>へ追加した際、表示状態のままだとフェードインをしないでパッと表示されてしまうため、最初に消しておきます。

先ほど、デフォルトのツールチップを非表示にしたコードの下あたりに一行コードを追加します。

// デフォルトで表示されるツールチップを消す
$this.attr("title", "");

// ↓ 追記
// 最初ツールチップは非表示にしておきます
$tooltip.hide();

// イベントの設定
$this

フェードイン・アウトをつける

マウスが乗った時、離れた時それぞれにアニメーションを追加していきます。
mouseentermouseleaveイベント内をそれぞれ次の様に変更します。

// イベントの設定
$this
  // マウスが乗ったら...
  .on("mouseenter", function(){

    // ...省略

    // 要素の上に横中央で配置
    $tooltip
      .css({
        top: offset.top - ttSize.height,
        left: offset.left + size.width / 2 - ttSize.width / 2
      })
      .stop(true, false)
      .fadeIn(500);
  })
  // マウスが離れたら...
  .on("mouseleave", function(){

    // <body>から、ツールチップを削除します
    $tooltip.stop(true, false).fadeOut(500, function(){
      $tooltip.remove();
    });
  });

アニメーションの実装について補足

fadeIn()fadeOut()の前につけている、stop(true, false)について少しだけ補足をしたいと思います。

jQueryを使ってアニメーションをする時、内部的にキューと呼ばれるアニメーション予約みたいなものが管理されています。マウスを乗せたり、離したりすることで複数回fadeIn()fadeOut()が呼ばれてしまい、このキュー(予約)がどんどん溜まっていきます。

そうすると、マウスでの操作をしていないのに、フェードイン・アウトを繰り返すおかしな挙動になってしまいます。
その変な挙動を抑えるためにstop()を使い、溜まっているキューをクリアして期待する動作に調整しています。

どういうことか分からない!という場合は、このstop()があるとき、無いときの挙動を実際に動かして試してみてください。なんとなく分かるかもです…!

最終的なコード

ここまで、最初のコードから少しずつ手を加えてきましたので最終的なコードを貼っておきます。

$(function(){

  var $body = $("body");

  // 各 `.my-tooltip` 要素に対して処理をしていきます
  $(".my-tooltip").each(function(){
    var $this = $(this); //何度か使うため、変数にしまっておきます
    var title = $this.attr("title"); //要素の`title`属性を取得

    // ツールチップ本体を生成します
    var $tooltip = $([
      "<span class='tooltip'>",
        "<span class='tooltip__body'>",
          title,
        "</span>",
      "</span>"
    ].join(""));

    // デフォルトで表示されるツールチップを消す
    $this.attr("title", "");

    // 最初ツールチップは非表示にしておきます
    $tooltip.hide();

    // イベントの設定
    $this
      // マウスが乗ったら...
      .on("mouseenter", function(){

        // <body>へツールチップを追加します
        $body.append($tooltip);

        // 要素の表示位置
        var offset = $this.offset();

        // 要素のサイズ
        var size = {
          width: $this.outerWidth(),
          height: $this.outerHeight()
        };

        // ツールチップのサイズ
        var ttSize = {
          width: $tooltip.outerWidth(),
          height: $tooltip.outerHeight()
        };

        // 要素の上に横中央で配置
        $tooltip
          .css({
            top: offset.top - ttSize.height,
            left: offset.left + size.width / 2 - ttSize.width / 2
          })
          .stop(true, false)
          .fadeIn(500);
      })
      // マウスが離れたら...
      .on("mouseleave", function(){

        // <body>から、ツールチップを削除します
        $tooltip.stop(true, false).fadeOut(500, function(){
          $tooltip.remove();
        });
      });
  });
});

まとめ

ちゃんとアニメーション付きでツールチップが表示されたでしょうか?
今回はプラグインを使わないで実装をしたので、次回からこれまで実装した内容をプラグインとしてまとめていきたいと思います。

  1. 【初心者向け】jQueryでツールチップのプラグインを自作しよう – Part1
  2. 【初心者向け】jQueryでツールチップのプラグインを自作しよう – Part2
  3. 【初心者向け】jQueryでツールチップのプラグインを自作しよう – Part3