4
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

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

Last updated at Posted at 2017-12-01

ページ全体を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でキャッシュさせています。

4
2
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
4
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?