ブレークポイントでDOMを生成しないようにする

Vue+Vuetifyで作っている以下のおもちゃの話。後でどこかにまとめて書くけど、とりあえずメモとして残す。

https://direboar.github.io/githubpage-test/dist/#/

ソースはこっち。
https://github.com/direboar/vue-vuetify-example/blob/master/src/components/SpellDetailDialog.vue

  • モバイルとデスクトップで同じシングルファイル・コンポーネントを使って表示するようにしている。
  • デスクトップでは、V-Datatableを使って一覧表示したい(ソートなどしたいため)
  • モバイルでは、V-Datatableは見切れるので、V-Listを使って表示したい項目を絞って出したい

という画面要求を満たすために、モバイル用とデスクトップ用の一覧表示を完全に別に作り、hidden-{breakpoint}-{condition}を使って、ブレークポイントで必要な一覧を表示するように制御していました。が、一覧の絞りこみが結構重たく、モバイルで動かすとかなり重たい。
試しにデバッガでDOMをみてみると、当然だけどhidden-{breakpoint}-{condition}で非表示にした要素も、DOMとして生成されている。重たい一覧表示を二重にやってりゃそりゃ重いよね…と思い、以下のようにしてブレークポイントで不要な画面はDOMごと消すようにした。

まず、computedプロパティに、モバイルかどうかを判定するメソッドを定義。

computed: {
 isMobile() {
   const mobileBreakpoints = ["xs", "sm"];
   return mobileBreakpoints.some(e => {
     return this.$vuetify.breakpoint.name === e;
   });
 }

次に、v-ifを使用してモバイル/非モバイルで表示を切り替えるコンポーネントについて、非表示時はDOM生成自体を行わないように制御。

<!--デスクトップ-->
<!--検索結果-->
<v-data-table v-if="!isMobile" :headers="headers" :items="items" item-key="name" no-data-text="条件に一致する呪文がありません。">
  <template slot="items" slot-scope="props">
    <tr @click="clickCell(props.item)">
      <td class="text-xs-left">{{ formatSpellName(props.item) }} </td>
      <td class="text-xs-left">{{ props.item.hoge }} {{ props.item.level}}</td>
      <td class="text-xs-left">{{ props.item.formatArray(props.item.components,components) }}</td>
      <td class="text-xs-left nowrap">{{ props.item.casting_time }}</td>
      <td class="text-xs-left">{{ props.item.formatDuration }}</td>
      <td class="text-xs-left">{{ props.item.range }}</td>
      <td class="text-xs-left">
        <v-icon>add</v-icon>
      </td>
    </tr>
  </template>
</v-data-table>

<!--モバイル-->
<!--検索結果-->
<v-list v-if="isMobile" dense two-line>
  <v-data-iterator content-tag="v-card" :items="items">
    <v-list-tile avatar slot="item" slot-scope="props" @click="clickCell(props.item)">
      <v-list-tile-content>
        <v-list-tile-title>{{props.item.name}} </v-list-tile-title>
        <v-list-tile-sub-title>{{props.item.level}}/{{props.item.format(props.item.school,schools)}}/{{props.item.formatArray(props.item.components,components)}}</v-list-tile-sub-title>
      </v-list-tile-content>
      <v-list-tile-avatar>
        <v-icon>add</v-icon>
      </v-list-tile-avatar>
    </v-list-tile>
  </v-data-iterator>
</v-list>

こんな感じで調整したら、モバイルの糞思い処理が、やや重いくらいに改善した。
根本解決にはなってないんですけどね。複数の検索条件を設定し、条件変更都度一覧の絞り込みをcomputedプロパティで行うようにしているだけなんですが…何が悪いんだろ?