JavaScript
Component
vuejs

vuejsのちょっと便利なコンポーネント機能

はじめに

vuejsはとっつきやすく完成度の高いJSフレームワークだと思っていますし、日本語のドキュメントも充実しています、実際に下記の機能も全て公式ドキュメントに記載されている内容です。

しかしながら、実際にやりたいことと機能名の間に乖離があったりして、いざ使用する時に意外に実装方法などを見つけにくい場合も当然ながら存在するため、自分用にvuejsのちょっと便利なコンポーネントの機能をメモっておきます。

お品書き

  • 共通した親要素を使いまわしたい(スロット配信)
  • パラメーターによって使用するコンポーネントを変えたい(動的コンポーネント)
  • 複数のコンポーネントで、同じ処理を使いまわしたい(ミックスイン)

共通した親要素を使いまわしたい

いわゆるラッパーコンポーネント、例えば10個のコンポーネントを作る必要があるとして、その全てが共通したヘッダやフッタを持っている場合というのは、そう珍しい状況ではないはず。

具体的にはこういう状況

ComponentA
<div>
<header>同じ内容</header>
<section>Aです!</section>
<footer>同じ内容</footer>
</div>
ComponentB
<div>
<header>同じ内容</header>
<section>Bです!Aじゃないです!</section>
<footer>同じ内容</footer>
</div>

つまり親要素は共通なんだけど、子要素はコンポーネントごとに違うという場合に、全部のコンポーネントにイチイチ同じ要素をコピペしてくるのは面倒だし、ヘッダー全部差し替えたいとかいう時に面倒。

そんな時は

Wrapper.vue
<div>
<header>同じ内容</header>

<slot></slot><!--ここに子要素が入ってくる-->

<footer>同じ内容</footer>
</div>
componentA
<Wrapper>
<section>Aです!</section>
</Wrapper>
componentB
<Wrapper>
<section>Bです!Aじゃないです!</section>
</Wrapper>

という感じで「スロットによるコンテンツ配信」を使えばOK!

Vuejs:スロットによるコンテンツ配信

パラメーターによって使用するコンポーネントを変えたい

さて、前述のように10個のコンポーネントを作ったとする、しかし実際にはヘッダーは全部同じじゃなくて、特定の場合だけヘッダーにボタンがついたりリンクがついたりする、というのもよくある話。

「ボタンを一つ追加する」くらいであれば、コンポーネント内でv-ifとか使ってなんとかすればいいと思いますが、それでは到底収まらないとか、面倒かつ可読性が悪化するなどの理由で、表示するヘッダ用のコンポーネントをあらかじめ複数用意しておいて、コンポーネントの親から渡ったpropsで表示するヘッダを判別する、というような実装にしたいとしましょう、その場合は

テンプレート側
<div>

<component :is="currentHeader"><!--ここで読み込むコンポーネントが動的に変わる-->

<slot></slot>
<footer>同じ内容</footer>
</div>
JS側
import IndexHeader from './IndexHeader.vue'
import SearchHeader from './SearchHeader.vue'
import ArchiveHeader from './ArchiveHeader.vue'

export default {
 props: ['currentHeader'],
 components: {
   Index: IndexHeader,
   Search: SearchHeader,
   Archive: ArchiveHeader
 }
}

という感じで、props の currentHeader で表示するコンポーネントを分岐できます。

Vuejs:動的コンポーネント

複数のコンポーネントで、同じ処理を使いまわしたい

さて、やはり10個のコンポーネントがあるとして、SPAでページ遷移する際にスクロール位置が保持されてしまい、そのままだと変な位置からページがはじまってしまうため、ページ遷移直後は常に画面の最上部までスクロールしたいとします。

JS例
created () {
  window.scroll(0,0)
}

もちろんこんな感じのコードを全てのコンポーネントに書いておけばそれは実現できますが、それだと特定のコンポーネントに書くのを忘れていたり、後に変更したいという場合にやはり面倒です、そういう場合

Init.vue
export default {
 created () {
   window.scroll(0,0)
 }
}

mixin
import Init from './Init.vue'

export default {
 name: '',
 mixins: [Init],/* ここでミックスインを追加 */
 components: {},
 data () {
   return {}
 }
}

という感じでミックスインを追加すると、複数コンポーネントで同じ処理を使いまわせます。

Vuejs:ミックスイン