😸

v-treeviewで行クリックでチェックを入れる方法

2022/07/03に公開

始めに

Vuetifyのv-treeviewでチェック機能をつけるができますが、行クリックではチェックがつかず、チェックボックスをクリックして初めてチェックがつくようになります。行選択でアクティブ化される機能とバッティングされるからでしょうけど、シンプルにチェックするだけの機能にしたい場合は少し使いづらいなと感じます。
そこでちょっとハックすることになりますが、行クリックでチェックさせることができたのでそのやり方をまとめたいと思います。
前提として、今回は以下のスクショのように親にチェックボックスを持たない場合の実装となります。

実装方法

今回は親はチェックを持たず、子だけチェックというカスタマイズをするので始めからselectableオプションは使わず自前で実装します。v-slot:prependでチェックボックスを表示し、チェック判定はactivatableオプションをつけてどのノードをクリックしたかをチェックして自前でフラグを立てます。

<template>
  <v-treeview
    // isChildやisCheckedフラグも含めたitemを渡す
    :items="_treeItems"
    // アクティブノード判定でどの行をクリックしたか判断する
    activatable
    :active="activeNodes"
    @update:active="onActive"
    // 今回はselectableオプションは使わない
    // selectable
  >
    <template v-slot:prepend="{ item }">
      <!-- 子要素のitemの時だけチェックボックスを表示する -->
      <template v-if="item.isChild">
        <v-checkbox
          :input-value="item.isChecked"
        />
      </template>
    </template>
  </v-treeview>
</template>

<script>
return Vue.extend({
  props: {
    treeItems: Array,
    selectedKeys: Array,
  },
  data() {
    return {
      activeNodes: [],
    };
  },
  computed: {
    _treeItems() {
      return this.$props.treeItems.map((item) => ({
        ...item,
	children: item.children.map((child) => ({
	  ...child,
	  isChild: true,
	  isChecked: this.$props.selectedKeys.includes(child.key),
	}),
      });
    },
  }
});
</script>

<style lang="scss">
::v-deep {
  // 親がslot:prependを使わないので幅を取らないようにスタイルを上書きする
  .v-treeview-node__content > .v-treeview-node__prepend {
    min-width: auto;
  }
}
</style>

onActiveメソッドではactiveになったキーを見てselectedKeyの状態をupdateさせます。

onActive(active) {
  const getChangeKey = (before, after) => {
    return after != null ? after : before;
  };
  const changeKey = getChangeKey(this.activeNodes[0], active[0]);
  this.activeNodes = active;
  
  this.$emit(
    'update:selectedKeys',
    this.$props.selectedKeys.includes(changeKey)
      ? this.$props.selectedKeys.filter((key) => key !== changeKey)
      : this.$props.selectedKeys.concat(changeKey)
  );
}

サンプルコード

後はこのコンポーネントを呼び出すだけで動きます。
サンプルをjsfiddleで書きましたので、詳細を見たい方はこちらをご参照ください。オンラインエディタの関係上Vue.jsはOptions APIで書かれておりますのでご了承ください。

終わりに

以上がv-treeviewで行クリックでチェックさせる方法でした。親要素も含めた場合ではselectableオプションをつけてvaluepropに対して行クリック判定時に増やしたり減らしたりでできると思います。ただ親についてはopen-on-clickと操作が被ってしまうので、どちらを優先するべきかを考えた上で実装する必要があると思います。
親も考慮に入れた場合はカスタマイズするのは大変ですが、子項目のみのチェックであれば比較的簡単にカスタマイズできるのでこちらの記事が参考になれば幸いです。

Discussion