はじめに
久しぶりのVue.jsに関する記事です。
今回は、以前記載させていただきました、JQueryとmark.jsでマークダウンのリアルタイムプレビューをつくるを書き換えたいと思います。
今までの記事はこちらになります。
- Vue.js入門その1〜基本文法〜
- Vue.js入門その2〜Vueインスタンスってなんぞ?〜
- Vue.js入門その3〜簡単にTODOアプリを作ってみたよ〜
- Vue.js入門その4〜TODOアプリにサーバーサイドを追加してみる〜
環境構築
JSFiddleを使用します。
設定方法などはVue.js入門その1〜基本文法〜をご参照ください。
- Vue.js: 2.2.1
- marked (cdn.js): 0.3.6
- lodash.js (cdn.js): 4.17.4
marked.jsの設定
CDNのロード
JSFiddleの左側、External ResourcesでCDNの設定をできます。
下記のリンクより、marked.jsのリンクを取得し、設定します。
(特に修正するわけではないので、min.jsのリンクを取得しました。)
marked
動作確認
HTMLの記述欄に記載して動くか確認してみます。
下図のように表示されるかと思います。
マークダウンを変換して表示
雛形の作成
変換の部分は後回しにし、画面表示とVueインスタンスだけ作成します。
簡易的にするため、formタグでは囲っていません。
HTML
v-modelを設定しておき、Vueインスタンスのinputプロパティと双方向バインディングをさせます。
JS
HTMLに変換して返す
Vueインスタンスに、マークダウンからHTMLに変換して返す処理を追加します。
このとき、getterとしても機能させてくれるcomputedを使用します。
やっていることはinputプロパティをmarkedメソッドで変換して返しているだけです。
これを変換後の文章を表示するエリアに埋め込みます。
innerHTMLをしてくれるv-html
HTMLを書き換えるときは、v-htmlが便利です。
これで指定したプロパティ、もしくはメソッドで書き換えてくれます。
ここまでで、変換はうまくいっているかと思います。
ただ、公式ドキュメントにも下記の通り記載がありますが、ユーザーからの入力をそのまま表示させると危険そうです。
任意の HTML をあなたの Web サイト上で動的に描画することは、XSS攻撃を招くため大変危険です。v-htmlは信頼済みコンテンツのみに利用し、絶対にユーザの提供するコンテンツには使わないでください。
サニタイズする
markedメソッドは第二引数でオプションの設定ができます。
https://github.com/chjj/marked
例えば、サニタイズしない場合は、下記のようにスクリプトを実行できます。
ここで、第二引数にsanitizeオプションを入れておきます。
タグをそのままエスケープしてくれるので、ひとまず安心です。
変換をまとめて行う
debounceを利用して、一定時間の間に行われた処理をまとめて実施したいと思います。
Vue.jsの1系ではv-modelにdebounce属性があったようですが、2系で削除されました。
v-modelのdebounce削除
ドキュメントを読むとlodash.jsが勧められていたので、そちらを使用したいと思います。
lodash.jsはJavaScriptのユーティリティライブラリで、debounce以外にも便利なメソッドがたくさんあるようです。
Lodash
今回はまたExternal Resourcesで読み込もうと思いますので、CDN版を利用します。
lodash.js
HTMLの書き換え
値が変わるたびに、debounceのメソッドを呼びたいと思いますので、v-modelはやめて、v-bindとv-onを使用します。
v-bindでは、textareaの値とinputプロパティを結びつけます。
v-onは特定のイベントが起きたときにメソッドを呼びます。
v-on:inputで、textareaの値が変化したら、関数を呼ぶようにします。
イベントリファレンス -input-
(関数はまだ実装していませんが、先に書いておきます。)
また、v-bind、v-onにはそれぞれ省略記法があるので、そちらで書き換えてみます。
updateValueメソッドの追加
lodash.jsの_.debounceを利用して、プロパティの変更をまとめて実施するようにします。
_.debounceの引数はそれぞれ下記のようになります。
- 対象の処理(関数)
- 時間(ミリ秒)
今回は0.5秒で変更するようにしました。
(主観ですが、1秒だとけっこう遅く感じます。)
0.5秒間隔でeventObjectから値を取得し、inputプロパティにセットします。
これで、処理がまとめて実施されるようになったのではないでしょうか?
さいごに
サンプルは下記になります。
CSSの方はお好みでお願いします。