Подтвердить что ты не робот

Связь между компонентами Sibling в VueJs 2.0

В vuejs 2.0 model.sync будет устарел.

Итак, что такое правильный способ связи между компонентами-братьями в vuejs 2.0?

Как я понимаю, идея в Vue 2.0 состоит в том, чтобы иметь связь с помощью магазина или шины событий.

Согласно evan:

Также стоит упомянуть, что "передача данных между компонентами" как правило, плохая идея, потому что в конечном итоге поток данных становится не поддающийся проверке и очень трудно отлаживать.

Если часть данных должна использоваться несколькими компонентами, предпочитайте глобальные магазины или Vuex.

[Ссылка на обсуждение]

и

.once и .sync устарели. Опоры теперь всегда в одну сторону вниз. к производить побочные эффекты в родительской области, компонент должен явно emit событие вместо того, чтобы полагаться на неявное связывание.

(Итак, он предлагает использовать $emit и $on)

Я беспокоюсь из-за:

  • Каждый store и event имеет глобальную видимость (исправьте меня, если я ошибаюсь);
  • Это много для создания нового хранилища для каждого младшего сообщения;

То, что я хочу, - это область как-то events или stores видимость для компонентов сиблингов. Или, может быть, я не понял эту идею.

Итак, как правильно общаться?

4b9b3361

Ответ 1

В Vue 2.0 я использую механизм eventHub, как показано в документации.

  1. Определите централизованный центр событий.

    const eventHub = new Vue() // Single event hub
    
    // Distribute to components using global mixin
    Vue.mixin({
        data: function () {
            return {
                eventHub: eventHub
            }
        }
    })
    
  2. Теперь в вашем компоненте вы можете генерировать события с

    this.eventHub.$emit('update', data)
    
  3. И слушать ты делаешь

    this.eventHub.$on('update', data => {
    // do your thing
    })
    

Обновление Пожалуйста, посмотрите ответ @alex, в котором описано более простое решение.

Ответ 2

Вы даже можете сделать это короче и использовать экземпляр root Vue качестве глобального Event Hub:

Компонент 1:

this.$root.$emit('eventing', data);

Компонент 2:

mounted() {
    this.$root.$on('eventing', data => {
        console.log(data);
    });
}

Ответ 3

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


Типы связи

Первое, что нужно понять при разработке приложения Vue (или фактически любого приложения на основе компонентов), - это то, что существуют разные типы связи, которые зависят от того, с какими проблемами мы имеем дело, и им нужны свои собственные каналы связи.

Бизнес-логика: относится ко всему, что относится к вашему приложению и его цели.

Логика представления: все, с чем взаимодействует пользователь или что является результатом взаимодействия с пользователем.

Эти две проблемы связаны с этими типами общения:

  • Состояние приложения
  • Родитель-ребенок
  • Ребенок-Родитель
  • Братья и сестры

Каждый тип должен использовать правильный канал связи.


Каналы связи

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

Реквизит (Презентационная логика)

Самый простой канал связи в Vue для прямого общения между родителями и детьми. Его в основном следует использовать для передачи данных, относящихся к логике представления или ограниченному набору данных, по иерархии.

Ссылки и методы (логика представления)

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

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

События (Логика презентации)

$emit и $on. Самый простой канал связи для прямого общения между ребенком и родителем. Опять же, следует использовать логику представления.

Шина событий (Оба)

Большинство ответов дают хорошие альтернативы для шины событий, которая является одним из каналов связи, доступных для удаленных компонентов, или чего-то еще.

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

Будьте осторожны: последующее создание компонентов, привязывающих себя к шине событий, будет связано более одного раза, что приведет к срабатыванию нескольких обработчиков и утечкам. Лично я никогда не чувствовал необходимость в шине событий во всех одностраничных приложениях, которые я разрабатывал в прошлом.

Далее показано, как простая ошибка приводит к утечке, когда компонент Item все еще срабатывает, даже если он удален из DOM.

// A component that binds to a custom 'update' event.
var Item = {
  template: '<li>{{text}}</li>',
  props: {
    text: Number
  },
  mounted() {
    this.$root.$on('update', () => {
      console.log(this.text, 'is still alive');
    });
  },
};

// Component that emits events
var List = new Vue({
  el: '#app',
  components: {
    Item
  },
  data: {
    items: [1, 2, 3, 4]
  },
  updated() {
    this.$root.$emit('update');
  },
  methods: {
    onRemove() {
      console.log('slice');
      this.items = this.items.slice(0, -1);
    }
  }
});
<script src="https://unpkg.com/[email protected]/dist/vue.min.js"></script>

<div id="app">
  <button type="button" @click="onRemove">Remove</button>
  <ul>
    <item v-for="item in items" :key="item" :text="item"></item>
  </ul>
</div>

Ответ 4

Хорошо, мы можем общаться между братьями и сестрами через родителя, используя события v-on.

Parent
 |-List of items //sibling 1 - "List"
 |-Details of selected item //sibling 2 - "Details"

Предположим, что мы хотим обновить компонент Details при нажатии какого-либо элемента в List.


в Parent:

Шаблон:

<list v-model="listModel"
      v-on:select-item="setSelectedItem" 
></list> 
<details v-model="selectedModel"></details>

Здесь:

  • v-on:select-item это событие, которое будет вызываться в компоненте List (см. ниже);
  • setSelectedItem это метод Parent для обновления selectedModel;

JS:

//...
data () {
  return {
    listModel: ['a', 'b']
    selectedModel: null
  }
},
methods: {
  setSelectedItem (item) {
    this.selectedModel = item //here we change the Detail model
  },
}
//...

В List:

Шаблон:

<ul>
  <li v-for="i in list" 
      :value="i"
      @click="select(i, $event)">
        <span v-text="i"></span>
  </li>
</ul>

JS:

//...
data () {
  return {
    selected: null
  }
},
props: {
  list: {
    type: Array,
    required: true
  }
},
methods: {
  select (item) {
    this.selected = item
    this.$emit('select-item', item) // here we call the event we waiting for in "Parent"
  },
}
//...

Здесь:

  • this.$emit('select-item', item) отправит элемент через select-item непосредственно в родительский. И родитель отправит его в представление Details

Ответ 5

Что я обычно делаю, если я хочу "взломать" обычные шаблоны связи в Vue, особенно сейчас, когда .sync устарел, заключается в создании простого EventEmitter, который обрабатывает связь между компонентами. Из одного из моих последних проектов:

import {EventEmitter} from 'events'

var Transmitter = Object.assign({}, EventEmitter.prototype, { /* ... */ })

С помощью этого объекта Transmitter вы можете сделать в любом компоненте:

import Transmitter from './Transmitter'

var ComponentOne = Vue.extend({
  methods: {
    transmit: Transmitter.emit('update')
  }
})

И создать "принимающий" компонент:

import Transmitter from './Transmitter'

var ComponentTwo = Vue.extend({
  ready: function () {
    Transmitter.on('update', this.doThingOnUpdate)
  }
})

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