Markdownでインタラクティブなページを作れるようにした

投稿日:

デモ

簡単なデモを用意しました。

正方形の面積

  • 一辺の長さ:
  • 面積: {{ len * len }}

文字列の長さ

  • 直径:
  • 長さ: {{ str.length }}

日付

  • 今日の日付: {{ today }}

このように、だいたいMarkdownだけ1で インタラクティブなページが作れる仕組みを作りました。

なぜ作ろうと思ったのか

Excel依存を減らしたい(止めたい)からです。 印刷するものについてはMarkdownでサクッと書くケースが多いのですが、 「式」を使う場合は、Excelが便利です。 ですが、この場合もMarkdownが使えないかなと考え、このシステムを作りました。

使っているもの

  1. Hugo
  2. Vue.js
  3. (オプション)その他JavaScriptライブラリ

仕組みの説明

1. コンテンツをdivで囲む

Vue.jsが制御する範囲として、 コンテンツを全部<div id="content">で囲んでいます。

2. YAML Front Matterで変数を定義

YAML Front Matterで2、以下のように変数を定義しています。

variables:
    len:
        type: number
        value: 20
    str:
        value: "abc"
computed:
    today:
        value: return moment().format("YYYY-MM-DD");

3. テンプレートでVue.jsに渡す変数を定義

variablesの内容を以下のように変換しています。

var vue_variables =
{
  "len":  20 ,
  "str": "abc",
};

同様に、computedの内容を以下のように変換しています。

var vue_computed =
{
  "today": function() { return moment().format("YYYY-MM-DD"); },
};

最後に、jQueryを使って3以下のように初期化しています。 vue_delimitersは、デリミタの定義で、 これもYAML Front Matterでカスタマイズ可能です。

var vue_delimiters = ["{{","}}"];
$(
  function() {
    init_vue(vue_variables, vue_computed, vue_delimiters);
  }
);

var vue;
function init_vue(variables, computed, delimiters) {
  vue = new Vue({
    delimiters: delimiters,
    el: '#content',
    data: variables,
    computed: computed
  });
}

4. shortcodeで入力フィールドを追加

Hugoのshortcode機能を使って、 {{< variable name="str" >}}のように記載すると4、 テキストフィールドや、セレクトボックスが出るようにしました。

5. 本文中にVue.jsのテンプレート構文を使って記載

例えば{{today}}のように書くと、{{ today }}のように変換されます。

課題

現在のところ以下の制限があります。

1. ハイライトとの相性が悪い

Prism.jsを使ってシンタックスハイライトを使っているのですが、 先に解釈されるようで、言語によってはテンプレート構文が使えません。 今のところは以下の方法で回避しています。

  • ハイライトを使わない
  • デリミタをカスタマイズ可能にして、ハイライトされないキーワードを使う

2. エラーが出た時に全体が消えてしまう

未定義の変数を使ったときなど、Vue.jsがエラーを出した時に、 全体が見えなくなってしまいます。

最後に

今回は方式のみ記載しましたが、 需要がありそうなら、テンプレートのコードを公開したいと思います。


  1. JavaScriptの知識がある程度必要ですが。 [return]
  2. HugoならTOML Fron MatterでもたぶんOK。 [return]
  3. BootstrapがjQueryを使っているので借用。 [return]
  4. テンプレートとして置換されないために分割して記載しています。 [return]