I have a Vue 3 App that i want to Call Global Component's Method from Another Component.
Here is the code:
//main.js
import { createApp, h } from 'vue';
import Loading from '@/components/Loading'; // Global Loading Component
const App = {
computed: {
ViewComponent () {
return require(`./views/Index.vue`).default
}
},
render () {
return h(this.ViewComponent)
},
}
const app = createApp(App);
app.component('Loading', Loading); // Adding it to Global
app.mount('#app');
//@/components/Loading.vue
<template>
<div id="darken"></div>
<div id="loading">
<img src="@/assets/images/loading.gif" />
</div>
</template>
<script>
export default {
name: 'Loading',
methods: {
showLoading(){
document.getElementById("darken").style.display = "inline";
document.getElementById("loading").style.display = "inline";
},
hideLoading(){
document.getElementById("darken").style.display = "none";
document.getElementById("loading").style.display = "none";
}
}
}
</script>
<style>
#darken {
position: absolute;
display: none;
top: 0;
left: 0;
width: 100%;
height: 100%;
background-color: black;
opacity: 0.5;
}
#loading {
position: absolute;
display: none;
left: 50%;
top: 50%;
transform: translate(-50%, -50%);
-ms-transform: translate(-50%, -50%); /* for IE 9 */
-webkit-transform: translate(-50%, -50%); /* for Safari */
}
#loading img {
width: 400px;
}
</style>
//@/views/Index.vue
<template>
<!-- Design Stuff ... -->
<button v-on:click="login()">Login</button>
<loading />
</template>
<script>
export default {
methods: {
login(){
//this.$refs.Loading.showLoading(); // this works when i add ref="Loading" to the <loading /> tag
// but i need something better, something like "this.$components.Loading.showLoading();"
// adding ref="Loading" with the loading tag is not convenient for me // is there alternative?
}
}
}
</script>
I Looked a lot and couldn't find what i am looking for.
Any ideas?, i would really appreciate it. Thank you.
PS: I am new to Vue.js but i am a fast learner.
CodePudding user response:
You have 2 options - shared functions and event bus.
With shared functions you have a file which exports barebone JavaScript functions and import the desired function(s) in every component where you need them - e.g. in Loading
and in Index
. Or, if you prefer - you may have several files with different Classes and then import and instantiate these classes where you need them. This method is suitable when you need functionality that does not depend on where it is used - that is, which is not tied to a specific component in your application. For example, if you need to export data to CSV from various places in your app - you can write a class (or a single function) which takes care of that and then use in anywhere you need the functionality.
If you need to signal something to a specific component in your application from another component (that is, to trigger some behvaior) - then you need an event bus. You can use mitt. Then in Loading
component you will subscribe for event like SHOW_LOADING and in Index
component you will emit the SHOW_LOADING event on the event bus.
CodePudding user response:
I Solved the issue.
The loading component has HTML and CSS which needs to be rendered globally and at the same time it contains methods that needs to be called globally.
So i found a solution which worked for me:
//main.js
import { createApp, h } from 'vue';
import Loading from '@/components/Loading'; // Global Loading Component
const App = {
computed: {
ViewComponent () {
return require(`./views/Index.vue`).default
}
},
render () {
return h(this.ViewComponent)
},
}
const app = createApp(App);
app.component('Loading', Loading); // Adding it to Global
app.config.globalProperties.Loading = Loading.methods; // ADDED NEW !!
app.mount('#app');
//@/views/Index.vue
<template>
<!-- // Design Stuff ... -->
<button v-on:click="login()">Login</button>
<loading /> <!-- // Leave it here or Put it in Main.vue Layout so it will be global in all renders -->
</template>
<script>
export default {
methods: {
login(){
// Newly Added
this.Loading.showLoading(); // This function can be accessed anywhere in Vue files
// do stuff
// finish stuff
this.Loading.hideLoading(); // This function can be accessed anywhere in Vue files
}
}
}
</script>