Riot.jsでコンポーネント間のデータのやり取りやDOM要素へのアクセス

Riot.jsで コンポーネント間のやり取り をする際によく使う方法を紹介します。他にも色々あるかもしれませんが、以下で紹介する方法で大体のことはできると思います。

親から子を参照

this.tags


<child>
  <script>
    this.item = '子要素のプロパティ';
  </script>
</child>

<parent>
  <child></child>

  <script>
    // マウントが終わったら子要素にアクセスできる
    this.on('mount', function() {
      // 子要素
      var child = this.tags.child;
      // 子要素のプロパティ
      var item = child.item;
    });
  </script>
</parent>

this.tags.タグ名 でネストしている子要素にアクセスできます。

this.refs


<child>
  <script>
    this.item = '子要素のプロパティ';
  </script>
</child>

<parent>
  <child ref="child"></child>

  <script>
    // マウントが終わったら子要素にアクセスできる
    this.on('mount', function() {
      // 子要素
      var child = this.refs.child;
      // 子要素のプロパティ
      var item = child.item;
    });
  </script>
</parent>

また、 ref 属性を設定すると、 this.refs.ref属性値 でアクセスできます。

子から親を参照


<parent>
  <child></child>

  <script>
    this.item = '親要素のプロパティ';
  </script>
</parent>

<child>
  <script>
    // 親要素
    var parent = this.parent;
    // 親要素のプロパティ
    var item = parent.item;
  </script>
</child>

this.parent で親要素にアクセスできます。

離れたコンポーネント間

riot.observable()


<one></one>
<other></other>

<script>
  riot.mount('*', {
    obs: riot.observable()
  });
</script>

<one>
  <button onclick="{click}">ボタン</button>
  <script>
    click() {
      opts.obs.trigger('button:clicked', '任意の値');
    }  
  </script>
</one>

<other>
  <script>
    opts.obs.on('button:clicked', function(data) {
      console.log('one要素のボタンがクリックされました');
      console.log(data); // 任意の値
    });
  </script>
</other>

riot.observable() を使うとイベントを利用して one 要素から other 要素に値を渡すことができます。

親要素経由


<parent>
  <one></one>
  <other></other>
</parent>

<one>
  <button onclick="{getTag}">ボタン</button>
  <script>
    getTag() {
      // other要素
      var other = this.parent.tags.other;
      // other要素のプロパティ
      var item = other.item;
    }
  </script>
</one>

<other>
  <script>
    this.item = 'other要素のプロパティ';
  </script>
</other>

ネストされていれば .parent.tags で辿れるのでそれを利用しています。

グローバルで管理


<one></one>
<other></other>

<script>
  var store = {
    item: ''
  };
  
  riot.mount('*');
</script>

<one>
  <button onclick="{getTag}">ボタン</button>
  <script>
    getTag() {
      // other要素でセットしたプロパティ
      var item = store.item;
    }
  </script>
</one>

<other>
  <script>
    store.item = 'other要素のプロパティ';
  </script>
</other>

グローバルにオブジェクトを定義しておいて、そこに状態などを保存しておく方法です。

riot.util.vdom


<one></one>
<other></other>

<script>
  riot.mount('*');

  function getTagByNode(node, context) {
    var tag = null;
    if (context == null) context = riot.util.vdom;

    // 現在探索中の階層が配列のとき(riot.util.vdomまたはtagsが配列のとき)
    if (Array.isArray(context)) {
      context.some(function(tags) {
        // 配列それぞれについて探索
        tag = getTagByNode(node, tags);
        // tagが初期値でない(見つかった)ときはループを抜けて値を返す
        if (tag !== null) return tag;
      });
    } else { // 現在探索中の階層がオブジェクトのとき
      // 見つかったら返す
      if (context.root === node) return context;
      // オブジェクトの数だけ探索
      for (var key in context.tags) {
        if (context.tags.hasOwnProperty(key)) {
          tag = getTagByNode(node, context.tags[key]);
          // tagが初期値でない(見つかった)ときはループを抜けて値を返す
          if (tag !== null) return tag;
        }
      }
    }

    return tag;
  }
</script>

<one>
  <button onclick="{getTag}">ボタン</button>
  <script>
    getTag() {
      // other要素
      var other = getTagByNode(document.querySelector('other'));
      // other要素のプロパティ
      var item = other.item;
    }
  </script>
</one>

<other>
  <script>
    this.item = 'other要素のプロパティ';
  </script>
</other>

riot.util.vdom にはマウントされた全てのカスタムタグが格納されているので、そこから取得するという方法もあります。

カスタムタグでないDOM要素にアクセス

.querySelector()


<element>
  <div class="title"></div>

  <script>
    this.on('mount', function() {
      var node = this.root.querySelector('.title');
    });
  </script>
</element>

マウント後であれば普通に .querySelector() 等の関数で取得することができます。

this.refs


<element>
  <div ref="title"></div>

  <script>
    this.on('mount', function() {
      var node = this.refs.title;
    });
  </script>
</element>

先ほども紹介しましたが、カスタムタグでなくても this.refs でアクセスできます。