ひよっこエンジニアの雑多な日記

なんとかWeb系のエンジニアをやっています。

【Vue.js】vue-routerとmathjaxを掛け合わせてみたら数式が変換されていなかった話

携帯にいつのまにか書いた2018年の目標に週1でブログを更新するという項目があったため今週も書きました(使命感)
最近技術記事書いてなかったし、ちょうど苦しめられたことがあったので備忘録をば

概要

vue-routerを使ってSPAチックなWebアプリを開発していて、コンポーネント内にmathjaxで数式を変換して表示するような箇所がありましたがvue-routerでコンポーネントレンダリングした箇所が数式を変換していないという問題が発生しました。。。
普通に画面遷移で作っていたときは変換されていたので完全に見落としてました。。。

再現

vue-cliでvueプロジェクトを作成

$ vue init webpack mathjax-test

index.htmlにmathjaxのCDNを配置する

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width,initial-scale=1.0">
    <title>mathjax-test</title>
  </head>
  <body>
    <div id="app"></div>
    <!-- 以下を追記 -->
    <script async src="https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.1/MathJax.js?config=TeX-AMS_CHTML"></script>
  </body>
</html>

ひとまず数式が表示されるか確認するためにsrc/App.vueに数式を設置してnpm run devを実行

<template>
  <div id="app">
    $$
    \begin{eqnarray}
    \sum^n_{k=1}a_k = S_n = a_1 + a_2 + ....+a_n
    \end{eqnarray}
    $$
  </div>
</template>
$ npm run dev

いい感じに表示されます。

f:id:kimuraysp:20180113164720p:plain

vue-routerを使ってクライアントサイドルーティングを実装する。
とりあえずコンポーネントを二つ作ってみる。

src/components配下にFormula1.vueとFormula2.vueを作成します。

<!-- Formula1.vue -->
<template>
  <div id="formula1">
    $$
    \begin{eqnarray}
    \sum^n_{k=1}a_k = S_n = a_1 + a_2 + ....+a_n
    \end{eqnarray}
    $$
  </div>
</template>

<script>
</script>

Formula2は適当に数式を変えて作成してください。
コンポーネントを作成したらrouterの設定を行います。

import Vue from 'vue'
import Router from 'vue-router'
import Formula1 from '@/components/Formula1'
import Formula2 from '@/components/Formula2'

Vue.use(Router)

export default new Router({
  routes: [
    {
      path: '/formula1',
      component: Formula1
    },
    {
      path: '/formula2',
      component: Formula2
    }
  ]
})

とりあえず/formula1/formula2というルーティングを作成して、リンクをクリックしたらそれぞれのコンポーネントを表示するようにします。
src/App.vueを以下のように書き換えます。

<template>
  <div id="app">
    <div class="links">
      <router-link to="/formula1">数式1</router-link>
      <router-link to="/formula2">数式2</router-link>
    </div>
    <router-view></router-view>
  </div>
</template>

vue-routerの書き方に沿ってリンクとコンポーネントの表示場所を作成します。
そして数式1をクリックしてみると。。。

f:id:kimuraysp:20180113164411p:plain

mathjaxが効いていない!!!/(^O^)\ナンテコッタ

普通に画面をレンダリングした時には効いていたのに、一体なんなのかと。。。

とりあえずmountedのタイミングでmathjaxを読み込むように修正

src/components/Formula1.vueのscriptsにを追記

export default {
  mounted() {
    MathJax.Hub.Queue(["Typeset", MathJax.Hub]);
  },
}

これで表示されるんとちゃいます?と数式1をクリックしたら数式が表示されました。

f:id:kimuraysp:20180113164443p:plain

mathjaxを利用しつつvue-routerを使う場合は数式が入ってくるであろうvueコンポーネントmountedのタイミングでmathjaxを読み込ませる必要があるようです。
createdのタイミングでは変換されず。。。

もしmathjaxとvue-routerを掛け合わせる時にはまっている人がいたら参考にどうぞ。。。

今回のソースコードも一応上げておきます。
https://github.com/kimuray/sandbox-vue-router-mathjax

最後に

これ実際に仕事ではめられた悲しみなんですが、仕事でやっていたときはmountedで読み込ませるだけでもダメで、createdのタイミングでも読み込ませるという二段構えをしないと数式が変換されませんでした。。。

仕事の環境はvue.js + Rails(しかも変換箇所はマークダウンで記載されている)みたいな感じだったのが何か影響していたのかなあ。。。

もしmountedにmathjax設定しても動かない場合はcreatedにもmountedと同じ記載をすれば動くかもしれないのでおためしあれ。。。