Vue.js で動的なファイルツリーを作る

概要

Vue.js で動的なファイルツリーを作ってみました。 ツリー表示 - Vue.js を参考にしました。

実装

実装をコメントと共に示します。

<html>
   <head>
      <script src='https://unpkg.com/vue/dist/vue.js'></script>
      <style>
         <!--
            .bold {
              font-weight: bold;
            }
            ul {
              line-height: 1.5em;
              list-style-type: dot;
              padding-left: 1em;
            }
            -->
      </style>
   </head>
   <body>
      <script type='text/x-template' id='item-template'>
         <li>
          <!-- 「:」は、 v-bind の省略記法。「@」は、 v-on の省略記法 -->
           <div :class='{bold: isFolder}' @click='toggle' @dblclick='changeFolder'>
             {{model.name}}
             <span v-if='isFolder'>[{{open ? '-' : '+'}}]</span>
           </div>

           <!-- v-show は、式の真偽値によって、表示・非表示をする。ここでは、フォルダの場合のみ、下の階層を表示します。 -->
           <ul v-show='open' v-if='isFolder'>
             <item v-for='model in model.children' :model='model' />
             <li class='add' @click='addChildFolder'>+</li>
           </ul>
         </li>
      </script>

      <ul id='folder'>
         <item :model='folderData' />
      </ul>

      <script type='text/javascript'>
         Vue.component('item', {
           template: '#item-template',
           props: {
             // Object オブジェクトは、全てのオブジェクトの基本オブジェクト。
             model: Object
           },
           data: function () {
             return {
               open: false
             }
           },
           // computed は、計算結果がキャッシュされる。
           computed: {
             isFolder: function () {
               return this.model.children && this.model.children.length
             }
           },
           methods: {
             toggle: function () {
               if (this.isFolder) {
                 this.open = !this.open
               }
             },
             changeFolder: function () {
               if (!this.isFolder) {
                 // Vue.set は、オブジェクトにプロパティを設定します。
                 Vue.set(this.model, 'children', [])
                 this.addChildFolder()
                 this.open = true
               }
             },
             addChildFolder: function () {
               this.model.children.push({
                 name: '新規フォルダ'
               })
             }
           }
         })

         const folderData = {
           name: 'ドラマ',
           children: [
             { name: '逃げるははじだが役に立つ' },
             { name: 'カルテット' },
             {
               name: 'ボク、運命の人です。',
               children: [
                 {
                   name: 'イントロダクション',
                 },
                 {
                   name: 'ストーリー',
                   children: [
                     { name: '#01' },
                     { name: '#02' }
                   ]
                 }
               ]
             }
           ]
         }

         new Vue({
           el: '#folder',
           data: {
             folderData: folderData
           }
         })
      </script>
   </body>
</html>

完成

こんな画面が出来ました。

f:id:takiy33kun:20170514142247p:plain