Vue 3.0でhighlight.jsを使って、整形したJSONに色を付けて表示

# はじめに

[整形したJSON](http://urusulambda.com/2020/08/30/%E3%80%90htmljavasciprt%E3%80%91web%E3%82%B5%E3%82%A4%E3%83%88%E3%81%A7json%E3%83%95%E3%82%A1%E3%82%A4%E3%83%AB%E3%82%92%E6%95%B4%E5%BD%A2%E3%81%97%E3%81%A6%E8%A1%A8%E7%A4%BA%E3%81%97%E3%81%9F/)を表示して、さらに色を付けたくなったら[highlight.js](https://highlightjs.org/)があります。
また、Vueでhighlight.jsを使おうと思えば、[Using with Vue.js](https://highlightjs.org/usage/)にある方法や、[vue-highlightjs](https://www.npmjs.com/package/vue-highlightjs)があります。
でもVue 3.0で使おうとしたら、どちらでも対応できません。
ではどうするのでしょうか。

# 準備

[vue-cliで手っ取り早くVue 3 + TypeScriptのプロジェクトを作ろう！](https://qiita.com/jesus_isao/items/0b305c7d90c45ad66c1b)を参考にVue 3.0のTypeScript環境を構築します。
そして`highlight.js`と、TypeScriptでコードを書くので`@types/highlight.js`を入れます。
npmを使いました。

```bash
npm install highlight.js @types/highlight.js
```

## ディレクトリ構成

src内のみ載せます。

```
src/
├── App.vue
├── main.ts
├── shims-vue.d.ts
├── assets
└── components
        └── highlight-json.vue
```

# コード

## App.vue

[前回同様](https://qiita.com/masayasviel/items/d6e8effa9dd0b35d0727#appvue)、`App.vue`の`state.content`にjsonデータをそのまま持たせています。

```vuejs
<template>
  <div id="app">
    <hljson :content="state.content"/>
  </div>
</template>

<script lang="ts">
import { defineComponent, reactive } from 'vue';
import hljson from './components/highlight-json.vue';

type State = {
  content: object;
};

export default defineComponent({
  name: 'App',
  components: {
    hljson
  },
  setup() {
    // property
    const state = reactive<State>({
      content: {
        "hoge": "fuga",
        "foo": "bar",
        "nums": [1, 2, 3, 4, 5, 6, 7, 8, 9, 0],
        "hashLists": [
          {
            "id": 0,
            "value": "a"
          },
          {
            "id": 1,
            "value": "b"
          },
          {
            "id": 3,
            "value": "c"
          }
        ],
        "bool-1": true,
        "bool-0": false
      }
    });
    return {
      state,
    };
  }
});
</script>
```

## highlight-json.vue

```vue
<template>
    <div class="highlight-json">
        <pre v-html="highlightJSON"></pre>
    </div>
</template>

<script lang="ts">
import { defineComponent, reactive, watch, computed } from 'vue';
import hljs from 'highlight.js';
import 'highlight.js/styles/xcode.css'; // ここでデザインを変更

type Props = {
    content: object;
};
type State = {
    content: object;
};

export default defineComponent({
    name: "highlight-json",
    props: {
        content: {
            type: Object,
            default() {
                return {}
            }
        }
    },
    setup(props: Props) {
        // property
        const state = reactive<State>({
            content: props.content
        });
        // watcher
        watch(props, (newVal) =>{
            state.content = newVal.content;
        });
        // computed
        const highlightJSON = computed(()=>
            hljs.highlightAuto(JSON.stringify(state.content, null , "\t"), ['JSON']).value
        );
        return {
            state,
            highlightJSON
        }
    }
});
</script>
```

[Node.js でファイルを保存する方法](https://qiita.com/phi/items/b5ade0c2ecc58935e046)を参考に、`JSON.stringify(state.content, null , "\t")`でJSONを整形、[【HTML+JavaSciprt】WebサイトでJSONファイルを整形して表示したい](http://urusulambda.com/2020/08/30/%E3%80%90htmljavasciprt%E3%80%91web%E3%82%B5%E3%82%A4%E3%83%88%E3%81%A7json%E3%83%95%E3%82%A1%E3%82%A4%E3%83%AB%E3%82%92%E6%95%B4%E5%BD%A2%E3%81%97%E3%81%A6%E8%A1%A8%E7%A4%BA%E3%81%97%E3%81%9F/)にある通り、`<pre></pre>`に整形したJSON文字列を突っ込んでいい感じに表示します。
でもそれだけだと色がつかないので、[highlightAuto](https://tr.you84815.space/hljs/api/highlight-auto.html)を使ってタグを付けます。
`{{ highlightJSON }}`だとinnerTextになってしまうので、`v-html`を使ってinnerHTMLにしてやります。
`import 'highlight.js/styles/xcode.css'; `の部分でデザインを変えられます。[コードのハイライト表示用 JS ライブラリ highlight.js の使い方](https://qiita.com/tadnakam/items/99088d78512a20e75ff3)を参考にしてください

これで`npm run serve`で以下のように表示されます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/299962/de6ff66f-4007-80be-4c3d-179a24bddccc.png)

# おわりに

これで名実ともにJSON色付け係というわけだ。

# 参考
- [highlight.js](https://highlightjs.org/)
- [highlight.jsドキュメント翻訳](https://tr.you84815.space/hljs/index.html)
- [【TypeScript】マークダウン文字列をHTMLにパースする(GitHub Flavored Markdown)](https://qiita.com/kou_pg_0131/items/015a714e0e3dc8bb5eb5)