JavaScript
riot
riot.js
Riot.jsDay 2

Riot.jsのタグオブジェクトを探す

More than 1 year has passed since last update.

ページ全体をRiotで作っている場合はあまり問題にならないかもしれませんが、「HTMLの中にRiotタグが散在している」かつ「Riotのマウントと別な箇所でタグを使った処理をしたい」というような状況下では、「あとからページにセットしたRiotタグのオブジェクトを取得したい」という場面が生じてきます。

これは、Riotのデータ構造をたどることで実現可能です。

Riotのデータ構造

グローバルにある状況であればグローバルのriotconst riot = require('riot');としている場合はそのriotを使えますが、riot.util.vdomに、ページへマウントしたタグオブジェクトが配列となって入っています。

そして、タグオブジェクト自体(で、今回のテーマに関係するもの)には、以下のプロパティがあります。

  • tag.root…対応するDOMノード
  • tag.tags[子タグ名]…このタグの中に存在する別のRiotタグ。1個ならタグオブジェクトがそのまま入っていて、複数なら配列となっている。

ということで、riot.util.vdomからtagsを再帰的にたどれば目的のことをできそうです。

実際に書いてみた

get_riot_tag.js
// WeakMapがある場合はキャッシュさせる

let cache = null;
if(window.WeakMap){
  cache = new WeakMap;
}


function getRiotTag(elem, current = riot.util.vdom) {
  if(typeof elem === 'string') {
    // セレクタで回せるように
    elem = document.querySelector(elem);
  }
  if(cache) {
    const cached = cache.get(elem);
    if(cached) return cached;
  }
  let ret = null;
  if(Array.isArray(current)) {
    // 最初のvdom、あるいはtagsが配列だった時
    current.some(item => {
      ret = getRiotTag(elem, item);
      return ret;
    });
  } else {
    // currentがタグの場合
    // キャッシュに入れる
    if(cache) cache.set(current.root, current);
    // 自分自身をチェック
    if(current.root === elem) return current;
    for(const key in current.tags) {
      ret = getRiotTag(elem, current.tags[key]);
      if(ret) return ret;
    }
  }
  return ret;
}

なお、「何度も走査するのを避ける」のと「DOMがなくなればキャッシュも確実に破棄させる」ために、WeakMapでキャッシュさせています。