LoginSignup
21
15

More than 5 years have passed since last update.

VueでJSXを使ってテキスト中のURLをaタグにする

Posted at

VueはtemplateプロパティにHTMLを書き、それにディレクティブを書くというスタイルで作っていきます。

new Vue({
  el: "#app",
  template: "<div>{{ text }}</div>",
  data: function(){
    return {
      text: "hello world"
    }
  }
})

▲普通にtemplateを使用したとき

image.png

これでも十分目的を果たせるのですが、 text に入れる文書にURLが入っており、それだけaタグにしたいというちょっと凝った要求は実現しにくいです。

そういった凝った要求には、Vueの2系列で使えるようになった render 関数を使うことで、テキストをパースして動的にHTMLをくみ上げていくということで満たすことが出来ます。

描画関数 - Vue.js

new Vue({
  el: "#app",
  render: function(createElement){
    return createElement("div", [this.text])
  },
  data: function(){
    return {
      text: "hello world"
    }
  }
});

render を使用したとき

ですが、render 関数を普通に使おうとすると引数として渡されてくる createElement でHTMLをくみ上げていくことになるので、HTMLを普通にくみ上げていくのに慣れている身としては少し使いづらい感じがします。

そこで、Vueでは render 関数にJSXを使うことが出来るので、それを利用してHTMLを組むのに近い感覚で凝った要求を満たそうと思います。

パッケージのインストールとJSXの使用

まずJSXを使用するには babel-plugin-syntax-jsx babel-plugin-transform-vue-jsx babel-helper-vue-jsx-merge-props をインストールします。これをインストールすると render 内でJSXを書くことが出来るようになります。

上の例をJSXで書くと以下のようになります。

new Vue({
  el: '#app',
  render (h) {
    return <div>
      { this.text }
    </div>
  },
  data: function(){
    return {
      text: "hello world"
    }
  }
});

render でJSXを使ったとき

テキスト中のURLをaタグにする

JSXで書けるようになったので、テキスト中のURLをaタグにする処理を書いてみます。少し無理矢理感が否めませんが以下のように書きました。

const regex = /http(:\/\/[-_.!~*¥'()a-zA-Z0-9;\/?:¥@&=+¥$,%#]+)/

new Vue({
  el: '#app',
  render (h) {
    let processTextArray = this.parseText();
    return <div>
      { processTextArray.map((text) => {
        if(text.match(regex)) {
          return <a href={text}>{text}</a>
        } else {
          return text
        }
      })}
    </div>
  },
  data: function(){
    return {
      text: "hello world http://www.google.com/ http://www.facebook.com/"
    }
  },
  methods: {
    parseText: function(){
      let processText = this.text

      let match
      let matchObj = {}
      let count = 0

      while ((match = regex.exec(processText)) != null) {
        count += 1
        matchObj[`[${count}]`] = match[0]
        processText = processText.replace(match[0], `[${count}]`)
        console.log(processText)
      }

      const keys = Object.keys(matchObj)

      keys.forEach((key) => {
        processText = processText.replace(key, `,${matchObj[key]},`)
      })
      return processText.split(',')
    }
  }
});

▲ テキストを処理するメソッドを用意する

テキストを処理するメソッドを用意し、そこから得られた文字列の配列がURLだったときaタグにするようにしています。

メソッドの処理としては簡単にURLがマッチしたら [1] のような特定できる適当な文字列で置き換え、置き換えたものを再度 , をつけたURLで置き換え、最後に , で分割しています。

多分もっと良いやり方があると思うのですが、いったんこれで目的を達することが出来ました。

まとめ

以上、VueでJSXを使い、DOMを構築してみました。createElement を使ったやり方よりもわかりやすくDOMを構築できたと思います。URLをパースする方法はもうちょっと良い方法がある気がしますが、これは今後の課題にしておきます。

21
15
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
21
15