Vue コンポーネント

登録・利用

呼び出し

※html
<div id="app">
 <hello />
</div>

グローバル登録

※js
Vue.component('hello', {
 template: `<div>Hello {{ name }}!</div>`,
 data: function(){
  return {
   name: 'global',
  };
 }
});

new Vue({
 el: '#app',
});

結果→Hello global!

ローカル登録

※js
let hello = {
 template: `<div>Hello {{ name }}!</div>`,
 data: function(){
  return {
   name: 'local',
  };
 }
};

new Vue({
 el: '#app',
 components: {
  'hello': hello,
 }
});

結果→Hello local!

props

親→子へデータ送信

※html
<div id="app">
 <hello name="props利用" />
</div>

※js
let hello = {
 template: `<div>Hello {{ name }}!</div>`,
 通常
 props: ['name']

 型制限
 props: {
  name: {
   type: String, String/Number/Boolean/Function/Object/Array/Date/Symbol
   required: true, true/false

   規定値
   default: '〜',

   規定値(Object型)
   default: function(){
    return {
     value: 'test'
    }
   }

   検証ルール
   validator: 〜

   検証ルール例(5文字以下)   
   validator: function(value){
    return value <= 5;
   }
  }
 },
};

new Vue(〜);

結果→Hello props利用!

emit

子→親へデータ送信

※html(親)
<div id="app">
 {{ current }}
 plusイベント発生時、onPlusメソッドを実行する
 <counter step="1" v-on:plus="onPlus"></counter>
 <counter step="-1" v-on:plus="onPlus"></counter>
</div>

※js(子)
let counter = {
 template: `<button type="button" v-on:click="onClick">STEP:{{ step }}</button>`,
 props: ['step'],
 methods: {
  onClick: function(){
   親componentでplusイベントを発生させる
   this.$emit('plus', Number(this.step));
  }
 }
};

new Vue({
 el: '#app',
 components: {
  'counter': counter,
 },
 data: {
  current: 0,
 },
 methods: {
  onPlus: function(e){
   this.current += e;
  }
 }
});

refs

親→子へデータ送信

※html(親)
<div id="app">
 <my-child ref="child"></my-child>
</div>

※js(子)
let MyChild = {
 data : function(){
  return {
   message: '',
  }
 },
 template: `<p>子:{{ message }}</p>`,
};

new Vue({
 el: '#app',
 components: {
  'my-child': MyChild,
 },
 data: {
  message: '',
 },
 mounted: function(){
  this.$refs.child.message = '親から設定(this.$refs.child.message)';
 }
});

parent

子→親へデータ送信

※html(親)
<div id="app">
 <p>親:{{ message }}</p>
</div>

※js(子)
let MyChild = {
 template: `<p>子:{{ message }}</p>`,
 mounted: function(){
  this.$parent.message = '子から設定(this.$parent.message)';
  ↓ も可
  this.$root.message = '子から設定(this.$root.message)';
 }
};

new Vue({
 el: '#app',
 components: {
  'my-child': MyChild,
 },
});

slot

親→子へデータ埋め込み

※html(親)
<div id="app">
 米良太が子コンポーネントのslotタグに埋め込まれる
 <my-slot>米良太</my-slot>
</div>

※js(子)
let MySlot = {
 ゲストが親コンポーネントにより置換される
 template: `<div>Hello <slot>ゲスト</slot>!</div>`,
};

new Vue({
 el: '#app',
 components: {
  'my-slot': MySlot,
 },
});

結果→Hello 米良太!

名前付きslot(複数のslot利用)

<div id="app">
 <my-slot>
  <template v-slot:header>Welcome</template>

  Vue.js
  ↓ も可
  <template v-slot:default>Vue.js</template>

  <template v-slot:footer>Thank You…</template>
 </my-slot>
</div>

<script>
 let MySlot = {
  template: `
   <div>
    <header>
     <slot name="header">DEFAULT</slot>
    </header>
    <div>
     <slot>DEFAULT</slot>
     ↓ と同じ意味
     <slot name="default">DEFAULT</slot>
    </div>
    <footer>
     <slot name="footer">DEFAULT</slot>
    </footer>
   </div>`,
 };
 
 new Vue({
  el: '#app',
  components: {
   'my-slot': MySlot,
  },
 });
</script>


結果→
Welcome
Vue.js
Thank You…

動的コンポーネント

バナーの切り替え例

<div id="app">
 指定のコンポーネントを読み込み
 <component v-bind:is="curretBanner" />
</div>

<script>
 バナー用コンポーネント登録
 Vue.component('banner-member', {
  template: `
   <div class="banner">
    <h3>バナーHeder(member)</h3>
    <p>バナーBody(member)</p>
   </div>`,
 });
 Vue.component('banner-new', {
  template: 〜
 });
 Vue.component('banner-env', {
  template: 〜
 });
 
 new Vue({
  el: '#app',
  created: function(){
   let that = this;
   this.interval = setInterval(function(){
    0、1、2の数値を3秒毎に入れ替える
    that.current = (that.current + 1) % that.components.length;
   }, 3000);
  },
  beforeDestroy: function(){
   clearInterval(this.interval);
  },
  computed: {
   curretBanner: function(){
    バナー名の配列を返す
    return 'banner-' + this.components[this.current];
   },
  },
  data: {
   current: 0,
   components: [
    'member',
    'new',
    'env',
   ],
  }
 });
</script>

タブの利用例

<div id="app">
 <div id="container">
  <ul>
   <li v-for="tab in tabNames">
    <a href="#" v-on:click.prevent="onClick(tab)">{{ tabs[tab] }}</a>
   </li>
  </ul>
  ※タブの切り替え時に入力値を残す
  componentの値をキャッシュする
  <keep-alive>
   指定のコンポーネントを読み込み
   <component v-bind:is="currentTab" />
  </keep-alive>
 </div>
</div>

<script>
タブ用コンポーネント登録
 Vue.component('tab-member', {
  template: `
   <div class="tab">
    <input type="text" v-model="name" />
    <input type="submit" value="登録" />
   </div>
  `,
  data: function(){
   return {
    name: '',
   };
  },
 });
 Vue.component('tab-new', {
  template: `〜`,
 });
 Vue.component('tab-env', {
  template: `〜`,
 });
 
 new Vue({
  el: '#app',
  methods: {
   onClick: function(tab){
    this.current = tab;
   } 
  },
  computed: {
   tabNames: function(){
    return Object.keys(this.tabs);
   },
   currentTab: function(){
    return `tab-${this.current}`;
   },
  },
  data : {
   current: 'member',
   tabs: {
    'member': 'メンバー募集',
    'new': '新刊紹介',
    'env': '環境設定',
   },
  }
 });
</script>

Follow me!

次の記事

CORS