はじめに

Vue.js で矢印キーや Enter キーによるキーボード操作が可能なコンテキストメニュー(右クリックメニュー)を表示する方法。

調査/検証 したところ rawilk/vue-context を使うのが一番楽だったので、基本的には vue-context の使い方についてのまとめ。

TL;DR

  • rawilk/vue-context だとキーボード操作にデフォルトで対応
  • ネストは li.v-context__subul.v-context を使う
    • , キーによる階層の移動が可能
  • スタイルは .v-context li, .v-context li a:hover, .v-context li a:focus あたりで変更
この記事が参考になった方
ここここからチャージや購入してくれると嬉しいです(ブログ主へのプレゼントではなく、ご自身へのチャージ)
欲しいもの / Wish list

目次

  1. はじめに
  2. TL;DR
  3. 環境・条件
  4. 詳細
    1. 前置き: Vue.js でコンテキストメニューを表示する方法
    2. vue-context の使い方
      1. セットアップ
    3. 参考: vmaimone/vue-context-menu の場合
  5. まとめ
  6. 参考文献

環境・条件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
$ cat /etc/os-release
PRETTY_NAME="Debian GNU/Linux 10 (buster)"

$ node -v
v12.16.1

$ npm -v
6.13.4

$ npm ls vue
vue@2.6.11 | MIT | deps: none | versions: 263

$ npm ls vue-context
vue-context@5.1.0 | MIT | deps: 1 | versions: 20

詳細

前置き: Vue.js でコンテキストメニューを表示する方法

Vue.js のコンテキストメニュー表示する方法やライブラリは主に以下。(自分調べ)

自作は工数の関係で除外し、各ライブラリを試したところ以下の結果。

  • heynext/v-contextmenu
    • @keyup@keydown など設定してもキーボード操作ができなかった
  • vmaimone/vue-context-menu
    • tabindex を設定して @keyup@keydown を使えばキーボード操作できる
    • ただし、2017/08/01 でメンテがとまっている(※2020/04/05 時点)
  • rawilk/vue-context
    • デフォルトで矢印キーでのキーボード操作に対応
    • @keyup.enter を使えば Enter キーも使える

vue-context の使い方

セットアップ

参考: Installation | vue-context

npm i でインストール

1
2
3
4
$ npm i vue-context
...
+ vue-context@5.1.0
added 2 packages from 2 contributors and audited 1219016 packages in 13.898s
Vue の場合

componentsVueContext を設定

1
2
3
4
5
6
7
8
9
10
import Vue from 'vue';
import VueContext from 'vue-context';

new Vue({
...
components: {
VueContext
},
...
}).$mount('#app');
Nuxt の場合

source/plugins/vue-context.js を作成 ※名称は各自でお好みで

1
2
3
4
5
import Vue from 'vue'
import VueContext from 'vue-context';
import 'vue-context/dist/css/vue-context.css'

Vue.component('vue-context', VueContext);

source/nuxt.config.js を編集

1
2
3
4
5
6
7
...
plugins: [
...,
'@/plugins/vue-context', // 追加
...,
],
...
基本

参考: Basic Usage | vue-context

  • 右クリックメニューを有効化したい場所に @contextmenu.prevent="$refs.xxxx.open" を設定
  • 右クリックメニューを <vue-context ref="xxxx"> で作成
    • 中身は lia で作成
      • li だけだと tabindex が設定されず、矢印キー操作も効かないので注意
    • a にクリックイベントを設定したい場合は @click を設定する
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
<template>
<div>
<!-- 右クリックメニュー有効箇所 -->
<p @contextmenu.prevent="$refs.menu1.open">
右クリックでメニューの表示
</p>

<!-- 右クリックメニュー -->
<vue-context ref="menu1">
<li>
<a @click.prevent="onClick($event.target.innerText)">
Option 1
</a>
</li>
<li>
<a @click.prevent="onClick($event.target.innerText)">
Option 2
</a>
</li>
</vue-context>
</div>
</template>

右クリック時に、他の処理もさせたい場合は open($event) のように $event を引数として渡す。

1
2
3
<p @contextmenu.prevent="$refs.menu1.open($event); otherMethods();">
右クリックでメニューの表示
</p>

Enter キーで右クリックメニュー内の処理をさせたい場合は、冒頭にも書いたように @keyup.enter を使う。

1
2
3
4
5
6
7
8
9
10
11
<!-- 右クリックメニュー -->
<vue-context ref="menu1">
<li>
<a
@click.prevent="onClick($event.target.innerText)"
@keyup.prevent.enter.exact="onClick($event.target.innerText)"
>
Option 1
</a>
</li>
</vue-context>
ネスト

参考: Nested Menus - Advanced Usage Demo

ネストの親を li.v-context__sub に、子は ul.v-context li にする。多段ネストする場合も同様。

ネストされている場合、, キーによる階層の移動が可能。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
<vue-context ref="menu1">
<li>
<a @click.prevent="onClick($event.target.innerText)">
ネスト無し
</a>
</li>
<li class="v-context__sub"> <!-- 親に v-context__sub を付ける -->
<a @click.prevent="onClick($event.target.innerText)">
ネスト有り
</a>
<!-- 子の下層部分を ul.v-contest & li で作る -->
<ul class="v-context">
<li>
<a @click.prevent="onClick($event.target.innerText)">
ネスト1-ネスト無し
</a>
</li>
<li class="v-context__sub"> <!-- 多段ネストも同様 -->
<a @click.prevent="onClick($event.target.innerText)">
ネスト1-ネスト有り
</a>
<ul class="v-context">
<li>
<a @click.prevent="onClick($event.target.innerText)">
ネスト2-ネスト無し
</a>
</li>
</ul>
</li>
</ul>
</li>
</vue-context>
ネストのアイコン

ネストされていることを示すアイコンが豆腐になるので、お好みで変更する。
(ちゃんと調べてないので何が原因かは不明、デモページでも豆腐になっている。追加でフォントの読み込みが要るのかも。)

.v-context__sub>a:aftercontent を変更すれば OK。

1
2
3
.v-context__sub>a:after {
content: " > ";
}

ちゃんとやるなら FontAwesome の angle-right とか使うのが良い。
参考: Font Awesome 5 Freeで疑似要素(:after,:before)のcontent指定する場合 - Qiita

1
2
3
4
5
6
7
8
9
10
11
12
/* これは動作未確認 */
.v-context__sub>a::after {
font-family: "Font Awesome 5 Free";
content: "\f105";

-webkit-font-smoothing: antialiased;
display: inline-block;
font-style: normal;
font-variant: normal;
text-rendering: auto;
line-height: 1;
}
ホバー/フォーカス 時のスタイル変更

ホバー時のスタイルは .v-context li a:hover, フォーカス時のスタイルは .v-context li a:focus で変更可能。

1
2
3
4
5
.v-context li a:hover, .v-context li a:focus {
background-color: #46a0fc;
color: #fff;
cursor: pointer;
}
余白とか調整

.v-context, .v-context li, .v-context li a あたりを変更すると余白とか変更可能。

1
2
3
4
5
6
.v-context li a {
color: #333;
font-size: 14px;
line-height: 14px;
padding: 5px 14px;
}

参考: vmaimone/vue-context-menu の場合

以下を意識すれば実装できるはず。

  • <context-menu> 配下の <li>tabindex を設定
  • @keyup.enter@keyup.up などのイベントハンドラを 作成/設定

右クリックのコンテキストメニューを「vue-context-menu」で実装する | カバの樹 をベース(参考)にすると良いと思う。

ただ、rawilk/vue-context がデフォルトで矢印キーの移動に対応してるのに、わざわざ自前で実装するのは正直ダルいので、なら rawilk/vue-context でいいじゃん、という感じ。

まとめ

  • rawilk/vue-context だとキーボード操作にデフォルトで対応
  • ネストは li.v-context__subul.v-context を使う
    • , キーによる階層の移動が可能
  • スタイルは .v-context li, .v-context li a:hover, .v-context li a:focus あたりで変更

参考文献

関連記事

この記事が参考になった方
ここここからチャージや購入してくれると嬉しいです(ブログ主へのプレゼントではなく、ご自身へのチャージ)
欲しいもの / Wish list