Vue.jsを使用したons-tabbar(OnsenUI)のアイコンを自作画像に変更する


はじめに

MonacaとOnsenUIではVue.jsが使えますが、実際に使用した際にはいくつか立ちはだかる壁があります

そのひとつが、 v-ons-tabbar のタブボタンに設定できるアイコンが FontAwesome のものしか扱えない、という問題(?)です

本稿ではその問題を解決してみます

前提

  • Monaca LocalKitを使用します。(執筆時のバージョンは3.4.0でした)
  • この記事では、Monaca Localkitから選択できるテンプレートのうち、以下を使用しています
    • カテゴリ: OnsenUI and Vue.js
    • テンプレート: Onsen UI V2 Vue Tabbar
  • 一応、 v-ons-tabbarv-ons-navigator を複合的に使用しているアプリでも動作することを確認しておりますが、実装によっては上手く動かないかもしれません

目標

  • Monaca + OnsenUI + Vue.js で自作のアイコンをタブボタンに表示できるようにする

1. v-ons-tabbardata からiconlabel を削除する

既存の icon label を削除します
理由はそれぞれ次の通りです

  • icon パラメータでは自作の画像を設定することができない為
  • icon が無い状態で label が定義されている場合、タブのボタン一面が label で指定した文字列いっぱいになってしまう為 (下記画像のようになります)
    • (2020/01/31追記: label の定義を削除すると、ツールバーに表示されているタイトルまで消えてしまいますので、削除してはなりません (別の方法でタブバーからラベルはご退場願う方法を追記しております))

サンプルコード




    data() {
      return {
        activeIndex: 0,
        tabs: [
        {
          // この icon と label を削除します (ここではコメントアウトで対応します)
          //icon: this.md() ? null : 'ion-home',
          label: 'Home',
          page: homePage
        },
        {
          //icon: this.md() ? null : 'ion-ios-bell',
          label: 'News',
          page: newsPage,
          badge: 7
        },
        {
          //icon: this.md() ? null : 'ion-ios-settings',
          label: 'Settings',
          page: settingsPage
        }
        ]
      };
    },

こんな感じになります

2. Vue.jsのオブジェクトに mounted() を追加し、その中で画像を表示するHTMLを追加する

続いて、javascript部分を記述していきます

Vueのライフサイクルから考えて、実際のビューを操作できるのは mounted() のタイミングですので、このタイミングで操作します

具体的には、 ons-tabbar__footer の中の孫要素にidをつけたdivを突っ込むという方法になります

document.querySelector(".ons-tabbar__footer").childNodes[0] という記述がありますが、この要素数がタブボタンのindexになっており、左から0, 1, 2とindexが増えるごとに右のボタンが指定されます。

setTimeout() していますが、これによって、実際に追加するタイミングをずらしています

本当はあまりよくない方法ですので、良い対応方法をご存じの方いらっしゃいましたらご教示くださいませ

サンプルコード


    mounted() {
      setTimeout(() => {
        const btnHomeImg = document.createElement("div");
        btnHomeImg.id = 'tabbtn_home';
        document.querySelector(".ons-tabbar__footer").childNodes[0].lastChild.appendChild(btnHomeImg);

        const btnNewsImg = document.createElement("div");
        btnNewsImg.id = 'tabbtn_news';
        document.querySelector(".ons-tabbar__footer").childNodes[1].lastChild.appendChild(btnNewsImg);

        const btnSettingImg = document.createElement("div");
        btnSettingImg.id = 'tabbtn_setting';
        document.querySelector(".ons-tabbar__footer").childNodes[2].lastChild.appendChild(btnSettingImg);
      }, 200)
    },
    components: { homePage, settingsPage, newsPage }
  }

3. スタイルシートでタブで表示するアイコンを指定する

最後に、スタイルシートで先ほど作成したidつきの <div> タグにスタイルを設定していきます

このタイミングで、タブバーの色を変更できます

また、バッチを使用している場合、下記記載のようなスタイル指定を行わないと、タブボタンに指定した画像が表示されなくなります

サンプルコード

(2020/01/31追記: 上記の手順でタブバーにラベルが表示されるようになりましたので、タブバーにラベルを表示しないスタイルを追加しました)

/*
 *タブバーの背景色 => アプリのイメージに合わせて適宜変更します
 */
.tabbar.ons-tabbar__footer.ons-swiper-tabbar {
    background: tan;
}

/*
 * タブバーでバッチを使用している場合、この指定が必要です。
 * バッチの上下の位置は top の値で変更できます (小さいほど上に移動)
 */
.tabbar__badge.notification {
  position: absolute;
  top: 20%;
}

/* 
 * タブバーからそれぞれラベルを削除する方法になります
 * display: none; で表示されなくなります
 */
.tabbar__label {
  display: none;
}

/*
 * ホーム画面のタブボタンの指定です
 */
#tabbtn_home {
    background-image: url(img/summer_uminoie.png);
    background-size: contain;
    background-repeat: no-repeat;
    background-position: center;

    margin: 6% 0;
    height: 55%;
}

/* 
 * ニュース画面のタブボタンの指定です
 */
#tabbtn_news {
    background-image: url(img/shinbun_girl.png);
    background-size: contain;
    background-repeat: no-repeat;
    background-position: center;

    margin: 6% 0;
    height: 55%;
}

/*
 * 設定画面のタブボタンの指定です
 */
#tabbtn_setting {
    background-image: url(img/haguruma.png);
    background-size: contain;
    background-repeat: no-repeat;
    background-position: center;

    margin: 6% 0;
    height: 55%;
}

完成

これで自作の画像 (今回はいらすとや様から拝借致しました、いつもありがとうございます) を指定できました

現状、OnsenUI + Vue.jsの場合、タブバーのアイコンを自作画像に変更するにはこの方法しかありません

このあたりが使いやすくなってくれるとありがたいですね。。。