30
23

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

Vue.js #1Advent Calendar 2017

Day 8

Web Components と vue-custom-elements

Last updated at Posted at 2017-12-07

ブラウザ対応が着々と進んできて、 Web Components の利用が現実味を帯びてきました。
そんななか、ざっと Web Components のおさらいと vue-custom-element に着目してみたいと思います。

Web Components とは?

  • Custom Elements
  • Shadow DOM
  • HTML imports
  • HTML Template

の4つの大きな仕様から構成される Web プラットフォーム API です。
Custom Elements で自由にカスタム要素を生成することができ、 Shadow DOM でカプセル化を促します。
Web Components の利用を簡潔に行うためのライブラリ Polymer なども存在しています。
これらの詳しい情報に関しては WEBCOMPONENTS.ORG にまとめられています。

Vue と Web Components の相性

Vue のテンプレート構文自体は HTML を拡張したような構文になっているので、Web Components はかなり親和性の高いものだと思います。
Custom Elements Everywhere でも、 Vue は満点評価になっています :heart_eyes:

Vue with Web Components

せっかくなので、Vue に Web Components を乗せてみました(DEMO

sample.png

ただ、 Web Components の現行の仕様の1つの HTML imports は ブラウザの実装状況 がよくなく、ES Modules ( HTML Modules ) に取って代わられるであろうとも云われています :disappointed_relieved:
(今回は ES Modules を利用していますので、Chrome などで閲覧願います!)

どちらもクリックをすると、カウントアップさせるようにしているのですが、

  • Vue Component : 通常通り vue-loader を利用した単一ファイルコンポーネント
  • Web Components : ボタンの見た目だけは Web Components、クリックイベント発火時の処理に関しては Vue に任せるような形

にしています。
開発者ツールでソースを確認していただけると、作りが全然異なっていることがわかるでしょう。
見た目だけの薄い作りにしておくことで、万が一 Vue 以外のフレームワークなどでもコンポーネントを利用したい( Web Components 部分のみ流用する形 )となったときに、融通が利きやすそうです。

Vue.config.ignoredElements = [
  'wc-button-red'
];

また、Vue のコンポーネントとして認識されないように、Web Components として登録しているコンポーネントを ignore 指定しておくことがポイントです。

Vue Costom Elements とは?

こちらは Vue コンポーネントのラッパーライブラリになります。
Web Components の Custom Elements 機能を利用(Polyfillも勿論あります)しており、Vueコンポーネントをカスタム要素として抽出・登録 をすることができます。
素の状態で利用したり、Vue.js 以外のコンポーネント指向フレームワーク(ライブラリ)などでも使用したりなどが可能になります(そんなユースケースはあまり存在しないかもしれませんが...)

vue-custom-elements に触れてみる

ここから先は特に DEMO を作成していません。
スクショを貼っているので、何となく雰囲気を感じていただければ...

Vueコンポーネントをカスタム要素に登録

button.vue というコンポーネントがあったとして、 それを vce-button というカスタム要素として登録してみます。

button.vue
<template>
  <button>{{text}}</button>
</template>

<script>
export default {
  name: 'button',
  data () {
    return {
      text: 'ボタンです'
    }
  }
}
</script>

<style lang="scss">
button {
  font-size: 16px;
  cursor: pointer;
  color: #fff;
  padding: 1em 2em;
  background: royalblue;
}
</style>
main.js
import Vue from 'vue'
import vueCustomElement from 'vue-custom-element'
import Button from './components/button.vue'
Vue.use(vueCustomElement);

Vue.customElement('vce-button', Button); // ここで定義!!

<vce-button> のカスタム要素としてレンダリングが行われていますね!

sample01.png

CSSの展開はいつも通り style-loader での展開になるので、 scope を付けてClass名をハッシュ値に変換しておいた方がよさそうです。
この辺は vue-loader のお作法がそのまま活かされるようです。

ShadowDOM の利用

Optional で ShadowDOM を利用することもできます。
ShadowDOM を利用する場合は、 vue-loader<style> 要素部分は無視されます。

main.js
Vue.customElement('vce-button', Button, {
  shadow: true,
  shadowCss: `
    button {
    font-size: 16px;
    cursor: pointer;
    color: white;
    padding: 1em 2em;
    background: royalblue;
  `
});

sample02.png

Props の利用

コンポーネント間は勿論のことですが、カスタム要素として登録する際に、その子どもにあたるコンポーネントに Props を渡すこともできます。

index.html
<body>
<!-- props で suffix を渡す -->
<vce-button suffix="か?" />
<script src="./dist/build.js"></script>
</body>
button.vue
<template>
  <button>{{text}}{{suffix}}</button>
</template>

<script>
export default {
  name: 'button',
  props: {
    'suffix': String,
  },
  data () {
    return {
      text: 'ボタンです'
    }
  }
}
</script>

sample04.png

Slot の利用

いつもの感覚で slot を利用することもできます。

index.html
<body>
<vce-button>
  <span vue-slot="prefix">私は</span>
  ボタンです
</vce-button>
<script src="./dist/build.js"></script>
</body>
button.vue
<template>
  <button>
    <!-- いつもの事ながら、名前付きslotの初期値を入れておける -->
    <slot name="prefix">これは!!!</slot><slot></slot>
  </button>
</template>

sample03.png

Vue の UI ライブラリを入れてみる

ライブラリの DEMO のところを見てみると、
しれっと当然のように、Vue の UI ライブラリである Element が内包されたカスタム要素を作成していたりします。
原理的には、Vue のコンポーネントで有りさえすればどのような形でもカスタム要素は生成できるみたいです。
ただ、その分当たり前ですが JS のファイルサイズが跳ね上がるので、様子見ながらと云ったところでしょうか?

さいごに

Web Components が普及することで、 UI ライブラリの選択肢も Vue のものに限る必要がなくなってきますし、ライブラリ自体の製作者側の負担も減ってきそうです。
Web Components に触れる機会はこれからどんどん増えていくでしょうし、 Vue ももちろんですが今後の動向が気になるところですね!

30
23
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
30
23

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?