admin管理员组

文章数量:1414929

Here is my base App.vue that holds the router-view:

<template>
<div>
    <Navbar/>

    <div class="container-fluid">
        <router-view></router-view>
    </div>
</div>
</template>

<script>
import Navbar from './ponents/Navbar.vue';

export default {
    name: 'App',
    ponents: {
        Navbar
    }
}
</script>

In the Navbar.vue, I have a method:

methods: {
    getLoggedStatus(){
        console.log('asdasd')
    }
}

Lastly, I have a Login.vue that is loaded there on the router-view. I wanna acess the getLoggedStatus() from the Navbar.vue within Login.vue. How can I achieve this?

I tried putting a ref to the Navbar tag in App.vue:

<Navbar ref="navvy"/>

And calling in on the Login.vue with:

this.$refs.navvy.getLoggedStatus()

But it doesn't work.

Here is my base App.vue that holds the router-view:

<template>
<div>
    <Navbar/>

    <div class="container-fluid">
        <router-view></router-view>
    </div>
</div>
</template>

<script>
import Navbar from './ponents/Navbar.vue';

export default {
    name: 'App',
    ponents: {
        Navbar
    }
}
</script>

In the Navbar.vue, I have a method:

methods: {
    getLoggedStatus(){
        console.log('asdasd')
    }
}

Lastly, I have a Login.vue that is loaded there on the router-view. I wanna acess the getLoggedStatus() from the Navbar.vue within Login.vue. How can I achieve this?

I tried putting a ref to the Navbar tag in App.vue:

<Navbar ref="navvy"/>

And calling in on the Login.vue with:

this.$refs.navvy.getLoggedStatus()

But it doesn't work.

Share Improve this question asked Nov 5, 2019 at 11:22 Dran DevDran Dev 5197 silver badges21 bronze badges 2
  • Because refs is available in App.vue context i.e. this, not in Login.vue. IMHO I don't think it's a good strategy to get loggedStatus like this. – haMzox Commented Nov 5, 2019 at 11:40
  • @hamzox any suggestions? :/ – Dran Dev Commented Nov 5, 2019 at 11:51
Add a ment  | 

2 Answers 2

Reset to default 5

A ref only works on children. You're rendering <Navbar> within app, so you cannot call that ref from login. You can only access this.$refs.navvy from App.vue.

There are several solutions for your problem.

  1. Emit an event from Login to App, so App calls the method from a ref.

You can set a listener in the router-view, as:

<router-view  @loggedStatus="callLoggedStatus"  />

In your login, when you would want to call the navbar getLoggedStatus, you would instead emit that event:

this.$emit('loggedStatus')

And then in App.vue, you would defined a callLoggedStatus methods that call the ref:

callLoggedStatus() {
  this.$refs.navvy.getLoggedStatus();
}

Given that you add the ref to the <Navbar> ponent in the APP template.

This solution is arguably the most similar to your proposed code, but I think it is a mess and you should avoid it, since you can end up listening to a lot of different events in your App.vue.

  1. Use Vuex

I don't exactly know what getLoggedStatus does, but if you want to change how your navbar behaves when the user is logged in, you should probably setup a vuex store, so you register there wether the user is logged or not. Then in your navbar ponent you render things conditionally depending upon the user is logged or not.

@Lana's answer follows this idea, and is probably the closest to the official way to thins in Vue.

  1.  Use an event emitter

If you want to directly municate between ponents that are not in the same family, I think an event emitter is a reasonable choice. You could setup an application wide event emitter after creating the app:

const app = new Vue({...});
window.emitter = new Vue();

(in the example we use a new Vue as event emitter. There is also the 'events' module which allow to use a EventEmitter)

And then any ponent can use it to send messages, so Login could do:

window.emitter.$emit('user-logged', myCustomPayload);

And Navbar on the other hand could do:

window.emitter.$on('user-logged', function() {
  this.getLoggedStatus();
})

This last option is not well considered in the Vue munity -Vuex is preferred- but for small applications I think it is the simplest.

  1. The dirty hack

You can always export your ponent to window. In the Navbar created hook you could do:

created() {
  window.Navbar = this;
}

And then in Login.vue you could, at any time:

window.Navbar.getLoggedStatus()

And it will work. However, this is surely an anti pattern and can cause a lot of harm to your project maintainability if you start doing this with several ponents.

It looks like getLoggedStatus returns some global state of the app. Use Vuex for managing these global variables.

Create a store like this:

// Make sure to call Vue.use(Vuex) first if using a module system
const store = new Vuex.Store({
  state: {
    loggedStatus: 0
  },
  getters: {
    getLoggedStatus: state => {
      // to pute derived state based on store state
      return state.loggedStatus 
    }
  }
})

Use store.state.loggedStatus in any Vue-ponent to access the global state or use getters like store.getters.getLoggedStatus if you need to pute derived state based on store state.

本文标签: javascriptVueCall a method from a different component (uses vueroutes)Stack Overflow