例えばVue.jsでモーダルを実装し、それを開くフックは別なところに引っ掛けたい、みたいなパターンでどうするか?
EventBusを利用する
この解決として、EventBusというのが公式に提案されている
new Vue()
でインスタンスを生成し、それを仲介してイベントを疎通しあう、という物になる。
windowグローバルにイベントを飛ばしたりするのと実質は変わらないが、ある程度キレイに実装出来そうだと感じる。
Modalでのサンプル
ベース
今回の基礎となるModalEventはこういう感じでシンプル。
ModalEvent.js
import Vue from "vue"
export const ModalEvent = new Vue()
今回はModalのvue-js-modal
を利用する。
<!--HelloModal.vue -->
<template>
<modal name="hello-modal">
<div class="container">
Hello!
</div>
</modal>
</template>
<script>
import Vue from "vue"
import VModal from "vue-js-modal"
// ModalEventをimportする
import { ModalEvent } from "./ModalEvent"
Vue.use(VModal)
export default {
created(){
// created / mountedでMountEventをlistenさせて、modalを開く
ModalEvent.$on("openModal", () => {
this.$modal.show("hello-modal")
})
}
}
</script>
別々にmountしたvueコンポーネント
index.html
:
<div id="app">
<modal-open-button></modal-open-button>
<hello-modal></hello-modal>
</div>
:
Modalを開く側のボタンはこんな具合になる
<!--ModalOpenButton.vue-->
<template>
<div>
<button @click="onClick">Open from Vue</button>
</div>
</template>
<script>
import { ModalEvent } from "./ModalEvent"
export default {
methods:{
onClick(){
// クリックしたらイベントを発火
ModalEvent.$emit("openModal")
}
}
}
</script>
これでModalEvent
を介してイベントが疎通して開くようになる
jQueryの場合
あんまり用途は無い(ことが望ましい)が、jQueryから発火するのも出来るようになった。
index.html
<div id="app">
<div>
<button id="jquery-external-button">Open from jQuery</button>
</div>
<hello-modal></hello-modal>
</div>
import $ from "jquery"
import { ModalEvent } from "./ModalEvent"
$(function(){
$("#jquery-external-button").click(function(){
ModalEvent.$emit("openModal")
})
})
vanillaなjsからの発火
jQueryとさして変わらないが、もう一歩踏み込んでjQueryも使わない場合。
あまりキレイではないが、window
にModalEventを渡して呼び出せる。
import Vue from "vue"
export const ModalEvent = new Vue()
window.ModalEvent = ModalEvent
index.html
<div id="app">
<div>
<button id="vanilla-external-button">Open from Vanilla</button>
</div>
<hello-modal></hello-modal>
</div>
<!-- built files will be auto injected -->
<script>
document.onreadystatechange = function(){
var elm = document.getElementById("vanilla-external-button");
elm.onclick = function(){
window.ModalEvent.$emit("openModal");
}
}
</script>
おまけ:もうちょっとEventを整然とする
無造作にEventを飛ばすのを防ぐのに、methods
で限定しておくと少しは整然とするであろう。
ModalEvent.js
import Vue from "vue"
const OPEN_MODAL = "openModal"
export const ModalEvent = new Vue({
methods: {
emitOpenModal(event){
this.$emit(OPEN_MODAL, event)
},
onOpenModal(cb){
this.$on(OPEN_MODAL, cb)
}
}
})