3
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

Vue 3.0を用いてJSON形式のデータをツリー表示

Last updated at Posted at 2020-10-16

はじめに

Vue 3.0を書いていてJSONをツリー表示させたくなる機会がありました。
調べればjsTreevue-json-tree, vue-json-tree-viewなど出てきますが、今回はいずれも使わずにやってみます。

本記事の目標

{
    "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
}

上記のJSONデータが、


  • hoge: fuga
  • foo: bar
  • nums
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 0
  • hashLists
    • 0
      • id: 0
      • value: a
    • 1
      • id: 1
      • value: b
    • 2
      • id: 3
      • value: c
  • bool-1: true
  • bool-0: false

と表示されることを目指します。

環境

node v14.3.0
@vue/cli 4.5.6
Google Chrome 86.0.4240.75

vue-cliで手っ取り早くVue 3 + TypeScriptのプロジェクトを作ろう!を参考に作成したプロジェクト内でやっていきます。

ディレクトリ構成

src内だけ載せます。

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

コード

App.vue

state.contentにjsonデータをそのまま持たせています。

<template>
  <jsonToTree :content="state.content"/>
</template>

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

type State = {
  content: object;
};

export default defineComponent({
  name: 'App',
  components: {
    jsonToTree
  },
  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>

json-to-tree.vue

v-ifv-forを用いて再帰させることで実現しました。

<template>
    <div class="json-to-tree">
        <ul v-for="(value, key) in state.content" :key="key">
            <li v-if="!value || typeof value !== 'object'">
                <span v-if="!Array.isArray(state.content)">{{ key }}: </span>
                {{ value + "" }}
            </li>
            <li v-else>
                {{ key }}
                <json-to-tree :content="value"/>
            </li>
        </ul>
    </div>
</template>

<script lang="ts">
import { defineComponent, reactive, watch } from 'vue';

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

export default defineComponent({
    name: "json-to-tree",
    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;
        });
        return {
            state
        }
    }
});
</script>

<style scoped>
.json-to-tree {
    margin: 0;
    padding: 0;
}
</style>

解説

わかりにくいのでいくつか解説します。

  • <li v-if="!value || typeof value !== 'object'">
    object(ArrayとHashを想定)でない場合、出力します。
    ここで、!value || としているのは、nullの場合、typeof nullがobject型になってしまうためです。
  • <span v-if="!Array.isArray(state.content)">{{ key }}: </span>
    元がHashでなくArrayだった場合、keyの出力は要らないため、Array.isArrayを用いています。"元"がどちらかを見たいため、引数はstate.contentとしている点に注意してください。
  • {{ value + "" }}
    nullもfalseもundefinedも文字列にしないと表示されないため、文字列にしています。
  • <json-to-tree :content="value"/>
    もしobject(ArrayとHashを想定)だった場合、再帰させます。これで階層を表現します。

おわりに

とりあえずDOMツリーにできたので、ここからCSSで装飾して木構造らしくするなり、エディタのディレクトリ構造みたく開閉式で見やすくするなりしてくれればいいと思います。
簡単に書き殴ったんで誤字脱字はご容赦ください。
ありがとうございました。

3
1
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
3
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?