LoginSignup
1
1

More than 3 years have passed since last update.

Vue.js切り替えタブを、一つのコンポーネントに書く

Posted at

基礎から学ぶVue.jsの切り替えタブを、作り替えたい

参考にするお手本

■基礎から学ぶVue.js 切り替えタブ実装例
https://cr-vue.mio3io.com/examples/tab.html#%E3%83%87%E3%83%A2

Screen Shot 2020-02-25 at 16.10.54.png

上記の実装例では、
・index.vueという親コンポーネント、
・TabItem.vueという子コンポーネント
2つ.vueファイルに分けて切り替えタブを実装しています。

しかし今回の目的は

1つのファイルにまとめて切り替えタブを作っていきます。
つまるところ、index.vueだけで済むように作り替えていきます。

作り替えてみた、完成版

index.vue

<template>
  <div class="example">
    <div class="tabs">
      <template v-bind:value="currentId">
        <button
          v-for=" item in list"
          :key="item.id"
          @click="idClickHandler(item)"
          :class="[active(item.id), 'tab']"
        >{{ item.label }}</button>
      </template>
    </div>
    <div class="contents">
      <transition>
        <section class="item" :key="currentId">{{ current.content }}</section>
      </transition>
    </div>
  </div>
</template>

<script>
export default {
  data() {
    return {
      currentId: 1,
      list: [
        { id: 1, label: "Tab1", content: "コンテンツ1" },
        { id: 2, label: "Tab2", content: "コンテンツ2" },
        { id: 3, label: "Tab3", content: "コンテンツ3" }
      ]
    };
  },
  computed: {
    active() {
      return function(id) {
        return this.currentId === id ? "active" : false;
      };
    },
    current() {
      return this.list.find(el => el.id === this.currentId) || {};
    }
  },
  methods: {
    idClickHandler(item) {
      return (this.currentId = item.id);
    }
  }
};
</script>

<style scoped>
.tab {
  border-radius: 2px 2px 0 0;
  background: #fff;
  color: #311d0a;
  line-height: 24px;
}
.tab:hover {
  background: #eeeeee;
}
.active {
  background: #f7c9c9;
}

.contents {
  position: relative;
  overflow: hidden;
  width: 280px;
  border: 2px solid #000;
}
.item {
  box-sizing: border-box;
  padding: 10px;
  width: 100%;
  transition: all 0.8s ease;
}
/* トランジション用スタイル */
.v-leave-active {
  position: absolute;
}
.v-enter {
  transform: translateX(-100%);
}
.v-leave-to {
  transform: translateX(100%);
}
</style>



変更したところ

  • (親)v-modelと(子)$emitを使ってイベントと値を渡していた → v-modelを廃止して、@click後の処理をmethodsに書いた
  • (子)で使えていた算出プロパティ(computed)内の、this.idを使ったactiveクラス → computedでは引数が使えないため、function関数をそのまま返す処理に変更して引数を使えるようにした

気をつけるところ

computed内、methods内で使用する値は、当たり前ですが変更する箇所が多いです。
TabItem.vueで使用する際になぜ this.値 と使えてたかというと、propsで値をもらっていたことでdataオプションのように使用できた為です。
そのため、index.vue内で this.値 を使用したくても出来ません。
v-forで回したlist内のオブジェクトitemを選択しているよ〜と伝える必要があります。
それを常に引数で渡す!!ことを心がけると上手くいきます。
ちなみに、template(html)で指定する引数とscript内で指定する引数は名前が違っても構いません。が、分かりやすくはしてください。

JSの機能か?Vueの機能か?

私は常にこの2つで迷って、正解を見つけ出すのに時間かかったりしてました。
Vue歴もJS歴も浅い時には、つねに2つのドキュメントを行き来するのではないかなと思います。
その中で迷ったことはこちらです。

・current()computedで使用するelは、何なんだろう。

■MDN find()メソッド
https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/Array/find
Screen Shot 2020-02-25 at 17.20.20.png

なるほど、JSの機能なのですね。

以上

ありがとうございました。

1
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
1