Vue アプリそのものに対して props や emit を使う
Vue アプリそのものへ引数を渡して動的にアプリインスタンスを立ち上げたり、Vue アプリ内の emit
で発行されたイベントを Vue アプリの外から購読したかったり、なんてことがありました。
レアケースだと思いますが、試行錯誤してちょっと苦労したので備忘録的に残しておきます。
props
を使う
アプリインスタンスで createApp()
の第2引数に渡すだけです。
const AppComponent = {
props: ['name', 'job'],
setup(props) {
console.log(props.name)
console.log(props.job)
return {}
}
}
const app = createApp(
AppComponent,
{
name: '太郎',
job: 'エンジニア',
},
)
app.mount('#app')
こちらは公式の API リファレンス に書いてあります。
emit
を使う
アプリインスタンスで こちらの解決策を実現するのに少々苦労しました。
createApp()
の第2引数に onClick
のように、 on
から続くキャメルケースで関数を渡すと、 emit
で発行されたイベントを購読できます。
下記は speak
イベントを発行して onSpeak
で購読する例です。
const AppComponent = {
props: ['name', 'job'],
emits: ['speak'],
setup(props, { emit }) {
console.log(props.name)
console.log(props.job)
/** 話す */
function speak() {
const lines = `私の名前は${props.name}です!`
console.log(lines)
emit('speak', lines)
}
return { speak }
}
}
const app = createApp(
AppComponent,
{
name: '太郎',
job: 'エンジニア',
onSpeak: lines => {
console.log(`onSpeak:「${lines}」`)
},
},
)
app.mount('#app')
これに気づいたのは、 レンダー関数 API のページを眺めていたときです。
レンダー関数を使ってコンポーネントを定義する際に書くイベントリスナと同様の書き方でできるのでは、と試したところ案の定でした。
// イベントリスナーは onXxx として渡す必要があります
h('div', { onClick: () => {} })
ユースケース
そもそも「Vue アプリそのものへ引数を渡して動的にアプリインスタンスを立ち上げたり、Vue アプリで emit で発行されたイベントを Vue アプリの外から購読したかったり、なんてこと」あるん???って感じですね。
例えば CDN での利用でページの一部分にだけ Vue を使用しているときに使いそうな気がします。
もしくは、1つのページ内に複数の Vue アプリが共存するケースで、それぞれを連携するのに使えると思います。
私は Vue アプリ内でモーダルダイアログを実装するときにこれを使いました。
ベースとなる Vue アプリとは別に、モーダルダイアログの中はまた独立した Vue アプリとして構築したかったのです。
でも完全に独立したいわけではなく、モーダルダイアログに値を渡したいし、モーダルダイアログでイベントを発行してベースの Vue アプリで購読したい、というときに活用しました。
「Vue アプリを複数使用する」という点でこのダイアログ実装のヒントとなったのは、私が愛する Quasar Framework の Dialog です。ダイアログを開くときはダイアログ専用の Vue アプリ内に展開されます。
Dialog 以外にも Notify とか他にも同様の実装だったものがあった気がします。
Discussion