Vue – передать переменную из дочернего шаблона в App.vue

#vue.js #vue-component

#vue.js #vue-компонент

Вопрос:

Я прочитал о передаче переменных от дочернего к родительскому, используя $emit , но я пока не могу полностью понять это.

В App.vue у меня есть <header/> компонент для заголовка страницы, содержащий кнопку, которая управляет видимостью мобильной навигации. При нажатии он меняет свой класс:

 <button @click="toggleMobileNavigation" :class="isOpen ? 'is-open' : 'is-closed'">
 

Это <header/> js:

 export default {
  data() {
    return {
      isOpen: false,
    };
  },
  methods: {
    toggleMobileNavigation() {
      if(!this.isOpen) {
        this.isOpen = true;
      } else {
        this.isOpen = false;
      }
      this.$emit(this.isOpen)
    }
  }
}
 

App.vue:

 <Header />
<main id="main" tabindex="-1" class="main" :class="isOpen">
 

Очевидно, что это не работает, и я не могу понять, как правильно перехватить $emit .

Спасибо за любые советы!

Комментарии:

1. используйте vuex, или сделайте заголовок плагином, у которого есть своя собственная шина событий, или передайте глобальную :state="state" опору, вокруг которой есть header.isOpen prop, или добавьте ссылку в заголовок и получите доступ через this.$refs.header, или глобальную шину событий, или перейдите от this $root затем в заголовоккомпонент, есть несколько способов

Ответ №1:

Я бы сказал, что вы на правильном пути, этот дочерний элемент должен выдать какое-то событие, чтобы предупредить своего родителя о важном изменении.

Но вместо того, чтобы делать это в вашем компоненте заголовка:

       this.$emit(this.isOpen)
 

Укажите имя события:

       this.$emit('opened', this.isOpen)
      // or:
      if (this.isOpen) { 
          this.$emit('opened');
      } else {
          this.$emit('closed');
      }
 

Способ, которым вы перехватываете это событие в родительском компоненте (App.vue), должен быть:

 <Header @opened="handleOpenedEvent">  // will call method handleOpenedEvent
// alternatively:
<Header @opened="menuStatus = $event"> // $event contains data you supply as second argument to your this.$emit(name, ...) call

// @[eventname] is one way of doing it, v-on is the same:
<Header v-on:opened="handleEvent">
 

Комментарии:

1. Привет! Спасибо за ваш ответ, он вывел меня на правильный путь. Каким-то образом я также должен установить emits: ["sendnavigationstatus"] export default внутри дочернего шаблона. В любом случае, спасибо Джошуа и счастливого нового года!

2. Привет, Анна, я не знал, что это (свойство emits) необходимо, я пытался найти это в документах Vue, но не смог его найти. Не могли бы вы указать мне правильное направление? И вас с новым годом.

3. Спасибо, кое-что узнал! Я работал с Vue 2, поэтому я пропустил это!

4. У вас есть эта локальная переменная (пусть isOpen), о существовании которой Vue не знает. Я бы добавил isOpen в функцию данных, в navigationStatus() заменил локальную переменную isOpen на this.isOpen . Это должно сработать, по крайней мере, в Vue 2, я знаю, что так и будет ;-). Если вы используете Vue3 composition api с этими типами ссылок, возможно, посмотрите здесь: v3.vuejs.org/guide/composition-api-introduction.html

5. Еще одна вещь, которую следует отметить в отношении имен динамических классов, вы используете ее следующим образом: :class='{someClass: isOpen}' или :class=" 'dynamic-string' (isOpen ? 'opened' : '')"'