Reputation: 692
What i want to achieve is to build a loading vue directives,
function with v-loading directive will render spinner and block event till function promise resolve or reject.
What i had tried so far:
// mitt solution
// custom-component template
<custom-component v-loading:event="onEvent">
// custom-component script
setup(props, {emit}) {
function emitEvent() {
emit("event");
// bad: have to remember to write this extra line, and it is third party dependency
mittEmitter.emit("event");
}
}
So, any other solution to listen vue's event(not dom's native event) from vue's $emit?
LoadingDirective.ts
import { Directive } from "vue";
const Loading: Directive = {
mounted(el, binding) {
const eventName = binding.arg;
const onEvent = binding.value;
// I want to listen vue's event(eventName) here
// do something extra
onEvent(); // original onEvent() function to run in App.vue
// do something extra
}
};
export default Loading;
App.vue
<template>
<!-- when onEvent triggered, a spinner will be render in custom-component -->
<custom-component v-loading:event="onEvent" />
</template>
CustomComponent.vue
<script lang="ts">
import { defineComponent } from "vue";
export default defineComponent({
setup(props, {emit}) {
function emitEvent() {
// use only vue's emit
emit("event")
}
return {
onEvent
};
}
});
</script>
Upvotes: 2
Views: 4105
Reputation: 10382
The Vue 3 documentation recommends using an external library such as mitt
or tiny-emitter
.
<template>
<div id="app">
<custom-component v-loading="eventHandler" />
</div>
</template>
const emitter = mitt();
const customComponent = { template: '<h1>Example</h1>' };
const app = Vue.createApp({
components: { customComponent },
setup() {
setTimeout(() => {
emitter.emit('loadingEvent', { colour: 'Green' });
}, 1000);
const eventHandler = e => console.log('Handled!', e);
return { eventHandler };
},
});
app.directive('loading', {
mounted(el, binding) {
const func = binding.value;
emitter.on('loadingEvent', data => {
// your logic here...
func(data);
});
},
});
app.mount('#app');
Upvotes: 3