LoginSignup
14
9

More than 5 years have passed since last update.

Riot.js で bootstrap-carousel タグを実装

Last updated at Posted at 2016-05-12

概要

Riot.js というライブラリがあって最近話題です。

これを使って bootstrap の carousel を簡単に実装するためのカスタムタグを作ってみました。

確かにすごく簡単で、便利に使えそうです。

この記事は、次の記事とのマルチポストです:
http://dora.bk.tsukuba.ac.jp/~takeuchi/?%E3%83%97%E3%83%AD%E3%82%B0%E3%83%A9%E3%83%9F%E3%83%B3%E3%82%B0%2FRiot.js%2Fbootstrap-carousel%E3%82%BF%E3%82%B0%E3%82%92%E5%AE%9F%E8%A3%85

Bootstrap の carousel

Bootstrap を使うと、次のように画像が次々にスクロールする carousel を簡単に実装できます。

bootstrap-carousel.gif

実働サンプルはこちらです: http://jsbin.com/peqipi/2/edit?html,output

ただ簡単とはいえ

普通にやると、この程度のコードを書く必要があります。

  <div id="carousel-example-generic" class="carousel slide" data-ride="carousel" data-interval="1500">
      <!-- Indicators -->
      <ol class="carousel-indicators">
          <li data-target="#carousel-example-generic" data-slide-to="0" class="active"></li>
          <li data-target="#carousel-example-generic" data-slide-to="1"></li>
          <li data-target="#carousel-example-generic" data-slide-to="2"></li>
      </ol>

      <!-- Wrapper for slides -->
      <div class="carousel-inner">
          <div class="item active">
              <img src="http://placehold.it/800x400" alt="Caption #1">
              <div class="carousel-caption">
                  <h2>Caption #1</h2>
              </div>
          </div>
          <div class="item">
              <img src="http://placehold.it/800x400" alt="Caption #2">
              <div class="carousel-caption">
                  <h2>Caption #2</h2>
              </div>
          </div>
          <div class="item">
              <img src="http://placehold.it/800x400" alt="Caption #3">
              <div class="carousel-caption">
                  <h2>Caption #3</h2>
              </div>
          </div>
      </div>

      <!-- Controls -->
      <a class="left carousel-control" href="#carousel-example-generic" data-slide="prev">
          <span class="fa fa-angle-left"></span>
      </a>
      <a class="right carousel-control" href="#carousel-example-generic" data-slide="next">
          <span class="fa fa-angle-right"></span>
      </a>
  </div>
  • 11-28 行目に画像とキャプションが羅列されています
  • 4-6 行目は中央の白丸にあたるもので、画像の数だけ並べます
  • 32-37 行目は手動でスクロールするための左右のコントロールにあたります

例えば画像を1枚追加するとすると、11-28 行目と、4-6 行目を両方変えなければならず面倒ですし、何をやっているか見通しも悪いです。

Riot.js を使うと

上と同じ carousel を

<bootstrap-carousel interval="1500">
  <img src="http://placehold.it/800x400" alt="Caption #1">
  <img src="http://placehold.it/800x400" alt="Caption #2">
  <img src="http://placehold.it/800x400" alt="Caption #3">
</bootstrap-carousel>

と書けるようになります!

画像の url と caption を列挙するだけ、 これ以上シンプルにはならない形です。これなら画像を追加したり、キャプションを変更するのも簡単にできます。

Riot.js のカスタムタグ

<bootstrap-carousel interval="1500"> ... </bootstrap-carousel>

の部分がいわゆる「カスタムタグ」です。

Riot.js は html ソースに埋め込まれたこのようなカスタムタグを、 別に与えた変換規則を用いて html に変換してくれるライブラリです。

_innerHTML の利用

よくある Riot.js のカスタムタグの利用例では、タグの中身を空にして、

<bootstrap-carousel interval="1500" />

とか、

<bootstrap-carousel interval="1500"></bootstrap-carousel>

のような形で使っています。

しかし、ドキュメントにもあるとおり Riot.js は通常の html をカスタムタグで囲って使うことも許しています。

<bootstrap-carousel interval="1500">
  <!-- 任意の html -->
</bootstrap-carousel>

カスタムタグに囲われた innerHTML は通常 <yield /> を呼び出して利用します。

ただその方法では、出力する html のどこかに、innerHTML をそのままの形で取り込むことしかできず、 利用目的が限られてしまいます。

実はこの内容には javascript からも this.root._innerHTML としてアクセス可能なため、 下記コードではこれを利用しています。(innerHTML ではなく _innerHTML であることに注意して下さい)

bootstrap-carousel タグの実装

以下のコードを bootstrap-carousel.tag として用意し、 riot.js で javascript へコンパイルして使います。

実動サンプルはこちら: http://jsbin.com/qoduteguli/edit?html,output

bootstrap-carousel2.gif

<bootstrap-carousel>

  <div id="carousel-example-generic" class="carousel slide" data-ride="carousel"
    data-interval={ this.interval } data-pause={ this.pause }
    data-wrap={ this.wrap } data-keyboard={ this.keyboard }>
      <!-- Indicators -->
      <ol class="carousel-indicators">
          <li each={ this.items } data-target="#carousel-example-generic" data-slide-to={ index } class={ active: index==0 }></li>
      </ol>

      <!-- Wrapper for slides -->
      <div class="carousel-inner">
          <div each={ this.items } class={ item: true, active: index==0 }>
              <img src={ src } alt={ caption }>
              <div class="carousel-caption">
                  <h2>{ caption }</h2>
              </div>
          </div>
      </div>

      <!-- Controls -->
      <a class="left carousel-control" href="#carousel-example-generic" data-slide="prev">
          <span class="fa fa-angle-left"></span>
      </a>
      <a class="right carousel-control" href="#carousel-example-generic" data-slide="next">
          <span class="fa fa-angle-right"></span>
      </a>
  </div>

  <style scoped>
    .carousel-inner > .item {
      text-align: center;
    }
    .carousel-inner > .item > img {
      display: inline;
    }
    .carousel-inner .carousel-caption h2 {
      color: rgba(0,0,0,0.6);
      font-size: 40px;
      text-shadow: 0px 0px 5px rgba(255, 255, 255, 0.6),
                   0px 0px 10px rgba(255, 255, 255, 0.6);
    }
    .carousel-indicators li {
      background-color: rgba(0,0,0,0.4);
      box-shadow: 0 0 5px rgba(0,0,0,0.6);
      border-color: rgba(255,255,255,0.8);
      margin-left: 6px;
      margin-right: 6px;
    }
    .carousel-indicators li.active {
      border-color: rgba(255,255,255,0.8);
      background-color: rgba(255,255,255,0.8);
      margin-left: 6px;
      margin-right: 6px;
    }
    img {
      opacity: 0.8;
    }
  </style>

  <script type="coffee">
    @on 'update', ->
      @interval = opts.interval ? 5000
      @pause    = opts.pause    ? "hover"
      @wrap     = opts.wrap     ? true
      @keyboard = opts.keyboard ? true

      @items = for img, i in $(@root._innerHTML) when img.tagName == 'IMG'
        caption: img.alt
        src:     img.src
        index:   i
  </script>
</bootstrap-carousel>
  • 3-28 行目が html ソース
    • { } で囲まれた部分が javascript として解釈されて、結果に置き換えられる
    • { value: expr } の部分は、expr の評価結果が true なら value に、さもなければ空になる
    • each={ } のついたタグは与えられた配列と同じ数だけ繰り返される
  • 30-59 行目が css ソース
    • scoped としておくと、カスタムタグの下の要素にのみ適用される
    • type="scss" などを指定して、scss などで書くこともできる
  • 61-73 行目が javascript ソース
    • 変換前に一回呼ばれる
    • on('update', function(){ ... }); を呼ぶことで、値の更新時に処理を行える
    • 基本は this.variable に値を設定して、javascript で { this.variable } を参照する形
    • this.root._innerHTML でカスタムタグに囲まれた html ソースが得られる

コンパイルとマウント

上記のようなタグの定義は Riot.js で javascript に変換して呼び出すか、 riot.compile にソースを渡してやることでタグライブラリに取り込み、 riot.mount でカスタムタグを含んだ html へ適用します。

  riot.compile(tag_source);
  riot.mount('*');

イベントやオブザーバブル、ルートなど

ここでは使いませんでしたが、Riot には他にもいろいろ機能があるようです。

今後も徐々に使いながら慣れていこうと思います。

14
9
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
14
9