8 методов коммуникации компонентов в Vue, которые стоит собрать!

Vue.js HTML
8 методов коммуникации компонентов в Vue, которые стоит собрать!

Я уже писал статью о кратком изложении интервью Vue. Многие пользователи сети предположили, что существует множество способов общения между компонентами. Эта статья посвящена подведению итогов общения между компонентами.

Об авторе: koala, сосредоточив внимание на совместном использовании полного стека технологий Node.js, от JavaScript до Node.js, до серверной базы данных, я желаю вам стать отличным старшим инженером Node.js. [Руководство по развитию программиста] Автор, блог Github с открытым исходным кодомGitHub.com/koala-co Nth…

Vue — это фреймворк для обновления представлений на основе данных, поэтому для Vue обмен данными между компонентами очень важен, так как же передавать данные между компонентами? В первую очередь нам нужно знать, какие отношения существуют между компонентами во Vue, чтобы легче было понять способы их общения, так же, как идти домой на Новый год, сидеть в комнате незнакомых людей, как называть друг друга , то нам нужно сначала Знать, какие у вас с ними отношения. Описание отношений в компоненте vue:

image

Как показано на рисунке выше, компоненты A и B, A и C, B и D, C и E находятся в отношениях родитель-потомок; B и C — родные братья и сестры; A и D, A и E — отношения между поколениями; D и E - двоюродные братья (непрямые родственники) Мы классифицируем вышеуказанные отношения как:

  • Связь между родительским и дочерним компонентами
  • Коммуникация между компонентами, не являющимися родительско-дочерними (компоненты братьев и сестер, компоненты межпоколенческих отношений и т. д.)

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

один,props / $emit

родительский компонент черезpropsспособ передачи данных дочерним компонентам и$emitДочерние компоненты могут взаимодействовать с родительскими компонентами.

1. Родительский компонент передает значение дочернему компоненту

Ниже приведен пример, иллюстрирующий, как родительский компонент передает данные дочернему компоненту: в дочернем компонентеarticle.vueКак получить родительский компонент вsection.vueданные вarticles:['红楼梦', '西游记','三国演义']

// section父组件
<template>
  <div class="section">
    <com-article :articles="articleList"></com-article>
  </div>
</template>

<script>
import comArticle from './test/article.vue'
export default {
  name: 'HelloWorld',
  components: { comArticle },
  data() {
    return {
      articleList: ['红楼梦', '西游记', '三国演义']
    }
  }
}
</script>

// 子组件 article.vue
<template>
  <div>
    <span v-for="(item, index) in articles" :key="index">{{item}}</span>
  </div>
</template>

<script>
export default {
  props: ['articles']
}
</script>

Резюме: реквизиты могут передаваться только от компонента верхнего уровня к компоненту следующего уровня (родительско-дочерний компонент), так называемый односторонний поток данных. И реквизит доступен только для чтения и не может быть изменен, все модификации завершатся ошибкой и предупредят.

2. Дочерние компоненты передают значения родительским компонентам

для$emitМое собственное понимание таково:$emitСвяжите пользовательское событие, когда оператор выполняется, параметр ARG будет передан на родительский компонент, а родительский компонент будет прослушивать и получать параметры через V-On. Используйте пример, чтобы проиллюстрировать, как дочерний компонент может передавать данные в родительский компонент. На основании предыдущего примера нажмите на страницу, представленнуюariticleизitem, индекс, отображаемый в массиве в родительском компоненте

// 父组件中
<template>
  <div class="section">
    <com-article :articles="articleList" @onEmitIndex="onEmitIndex"></com-article>
    <p>{{currentIndex}}</p>
  </div>
</template>

<script>
import comArticle from './test/article.vue'
export default {
  name: 'HelloWorld',
  components: { comArticle },
  data() {
    return {
      currentIndex: -1,
      articleList: ['红楼梦', '西游记', '三国演义']
    }
  },
  methods: {
    onEmitIndex(idx) {
      this.currentIndex = idx
    }
  }
}
</script>
<template>
  <div>
    <div v-for="(item, index) in articles" :key="index" @click="emitIndex(index)">{{item}}</div>
  </div>
</template>

<script>
export default {
  props: ['articles'],
  methods: {
    emitIndex(index) {
      this.$emit('onEmitIndex', index)
    }
  }
}
</script>

два,$children / $parent

image
Картинка вышеvueофициальное объяснение через$parentа также$childrenВы можете получить доступ к экземпляру компонента, что представляет экземпляр? Делегат имеет доступ ко всем методам этого компонента иdata. Следующий шаг — как получить экземпляр указанного компонента.

инструкции

// 父组件中
<template>
  <div class="hello_world">
    <div>{{msg}}</div>
    <com-a></com-a>
    <button @click="changeA">点击改变子组件值</button>
  </div>
</template>

<script>
import ComA from './test/comA.vue'
export default {
  name: 'HelloWorld',
  components: { ComA },
  data() {
    return {
      msg: 'Welcome'
    }
  },

  methods: {
    changeA() {
      // 获取到子组件A
      this.$children[0].messageA = 'this is new value'
    }
  }
}
</script>
// 子组件中
<template>
  <div class="com_a">
    <span>{{messageA}}</span>
    <p>获取父组件的值为:  {{parentVal}}</p>
  </div>
</template>

<script>
export default {
  data() {
    return {
      messageA: 'this is old'
    }
  },
  computed:{
    parentVal(){
      return this.$parent.msg;
    }
  }
}
</script>

Имейте в виду крайние случаи, такие как в#appзанимать$parentполучить этоnew Vue(), взять этот экземпляр еще раз$parentполучить этоundefinedИ в нижней части подсборки взять$childrenЭто пустой массив. Также обратите внимание, что для получения$parentа также$childrenстоимость разная,$childrenЗначение представляет собой массив, а$parentявляется объектом

Суммировать

Вышеупомянутые два метода используются для связи между родительскими и дочерними компонентами, и использование props для связи между родительскими и дочерними компонентами более распространено; ни один из них не может использоваться для связи между компонентами, не являющимися родительскими и дочерними.

три,provide/ inject

концепция:

provide/ injectдаvue2.2.0Недавно добавленный API просто передается в родительский компонентprovideдля предоставления переменных, а затем передать дочерний компонентinjectвводить переменные.

Примечание. Независимо от того, насколько глубоко вложены здесь подкомпоненты, до тех пор, пока вызовinjectзатем вы можете ввестиprovideДанные в, не ограничиваясь возвратом данных из свойства props текущего родительского компонента

Пример проверки

Далее используется пример для проверки приведенного выше описания: Предположим, что есть три компонента: A.vue, B.vue, C.vue, где C — подкомпонент B, а B — подкомпонент A.

// A.vue

<template>
  <div>
	<comB></comB>
  </div>
</template>

<script>
  import comB from '../components/test/comB.vue'
  export default {
    name: "A",
    provide: {
      for: "demo"
    },
    components:{
      comB
    }
  }
</script>
// B.vue

<template>
  <div>
    {{demo}}
    <comC></comC>
  </div>
</template>

<script>
  import comC from '../components/test/comC.vue'
  export default {
    name: "B",
    inject: ['for'],
    data() {
      return {
        demo: this.for
      }
    },
    components: {
      comC
    }
  }
</script>
// C.vue
<template>
  <div>
    {{demo}}
  </div>
</template>

<script>
  export default {
    name: "C",
    inject: ['for'],
    data() {
      return {
        demo: this.for
      }
    }
  }
</script>

Четыре,ref / refs

ref: при использовании с обычными элементами DOM ссылка указывает на элемент DOM, при использовании с подкомпонентами ссылка указывает на экземпляр компонента, и вы можете напрямую вызывать методы компонента или получать доступ к данным через экземпляр.refЧтобы получить доступ к примеру компонента:

// 子组件 A.vue

export default {
  data () {
    return {
      name: 'Vue.js'
    }
  },
  methods: {
    sayHello () {
      console.log('hello')
    }
  }
}
// 父组件 app.vue

<template>
  <component-a ref="comA"></component-a>
</template>
<script>
  export default {
    mounted () {
      const comA = this.$refs.comA;
      console.log(comA.name);  // Vue.js
      comA.sayHello();  // hello
    }
  }
</script>

Пять, eventBus

eventBusТакже известная как шина событий, она может использоваться в качестве концепции коммуникационного моста в Vue, точно так же, как все компоненты используют один и тот же центр событий, вы можете зарегистрироваться в центре для отправки или получения событий, чтобы компоненты могли уведомлять другие компоненты.

Есть у eventBus и неудобства: когда проект большой, легко вызвать катастрофы, которые сложно поддерживать.

Как использовать его в проекте VueeventBusДля обеспечения обмена данными между компонентами? В частности, с помощью следующих шагов.

1. Инициализировать

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

// event-bus.js

import Vue from 'vue'
export const EventBus = new Vue()

2. Отправка событий

Предположим, у вас есть два компонента:additionNumа такжеshowNum, эти два компонента могут быть одноуровневыми компонентами или родительско-дочерними компонентами; здесь мы берем одноуровневые компоненты в качестве примера:

<template>
  <div>
    <show-num-com></show-num-com>
    <addition-num-com></addition-num-com>
  </div>
</template>

<script>
import showNumCom from './showNum.vue'
import additionNumCom from './additionNum.vue'
export default {
  components: { showNumCom, additionNumCom }
}
</script>

// addtionNum.vue 中发送事件

<template>
  <div>
    <button @click="additionHandle">+加法器</button>    
  </div>
</template>

<script>
import {EventBus} from './event-bus.js'
console.log(EventBus)
export default {
  data(){
    return{
      num:1
    }
  },

  methods:{
    additionHandle(){
      EventBus.$emit('addition', {
        num:this.num++
      })
    }
  }
}
</script>

3. Получать события

// showNum.vue 中接收事件

<template>
  <div>计算和: {{count}}</div>
</template>

<script>
import { EventBus } from './event-bus.js'
export default {
  data() {
    return {
      count: 0
    }
  },

  mounted() {
    EventBus.$on('addition', param => {
      this.count = this.count + param.num;
    })
  }
}
</script>

Это достигается в компонентеaddtionNum.vueНажмите кнопку «Добавить» вshowNum.vueпередано изnumОтобразить результат суммирования.

4. Удалить прослушиватели событий

Чтобы удалить прослушиватели событий, сделайте следующее:

import { eventBus } from 'event-bus.js'
EventBus.$off('addition', {})

6. Векс

1. Введение в Vuex

Vuex — это шаблон управления состоянием, разработанный для приложений Vue.js. Он использует централизованное хранилище для управления состоянием всех компонентов приложения и имеет соответствующие правила, обеспечивающие предсказуемое изменение состояния. Vuex решен多个视图依赖于同一状态а также来自不同视图的行为需要变更同一状态проблема, сосредоточьте усилия разработчиков на обновлении данных, а не на передаче данных между компонентами

2. Модули Vuex

  1. state: используется для хранения данных, является единственным источником данных в хранилище
  2. getters: как и вычисляемые свойства в Vue, основанные на вторичной упаковке данных состояния, они часто используются для фильтрации данных и расчета корреляции нескольких данных.
  3. mutations: похож на функцию, единственный способ изменить данные состояния и не может использоваться для обработки асинхронных событий.
  4. actions: что-то типаmutation, для подачиmutationдля изменения состояния без непосредственного изменения состояния, может включать произвольные асинхронные операции
  5. modules: Подобно пространству имен, оно используется для определения и управления состоянием каждого модуля отдельно в проекте для упрощения обслуживания.

3. Пример приложения Vuex

// 父组件

<template>
  <div id="app">
    <ChildA/>
    <ChildB/>
  </div>
</template>

<script>
  import ChildA from './components/ChildA' // 导入A组件
  import ChildB from './components/ChildB' // 导入B组件

  export default {
    name: 'App',
    components: {ChildA, ChildB} // 注册A、B组件
  }
</script>
// 子组件childA

<template>
  <div id="childA">
    <h1>我是A组件</h1>
    <button @click="transform">点我让B组件接收到数据</button>
    <p>因为你点了B,所以我的信息发生了变化:{{BMessage}}</p>
  </div>
</template>

<script>
  export default {
    data() {
      return {
        AMessage: 'Hello,B组件,我是A组件'
      }
    },
    computed: {
      BMessage() {
        // 这里存储从store里获取的B组件的数据
        return this.$store.state.BMsg
      }
    },
    methods: {
      transform() {
        // 触发receiveAMsg,将A组件的数据存放到store里去
        this.$store.commit('receiveAMsg', {
          AMsg: this.AMessage
        })
      }
    }
  }
</script>
// 子组件 childB

<template>
  <div id="childB">
    <h1>我是B组件</h1>
    <button @click="transform">点我让A组件接收到数据</button>
    <p>因为你点了A,所以我的信息发生了变化:{{AMessage}}</p>
  </div>
</template>

<script>
  export default {
    data() {
      return {
        BMessage: 'Hello,A组件,我是B组件'
      }
    },
    computed: {
      AMessage() {
        // 这里存储从store里获取的A组件的数据
        return this.$store.state.AMsg
      }
    },
    methods: {
      transform() {
        // 触发receiveBMsg,将B组件的数据存放到store里去
        this.$store.commit('receiveBMsg', {
          BMsg: this.BMessage
        })
      }
    }
  }
</script>

вексstore,js

import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex)
const state = {
  // 初始化A和B组件的数据,等待获取
  AMsg: '',
  BMsg: ''
}

const mutations = {
  receiveAMsg(state, payload) {
    // 将A组件的数据存放于state
    state.AMsg = payload.AMsg
  },
  receiveBMsg(state, payload) {
    // 将B组件的数据存放于state
    state.BMsg = payload.BMsg
  }
}

export default new Vuex.Store({
  state,
  mutations
})

Семь,localStorage / sessionStorage

Этот вид связи относительно прост, но недостатком является то, что данные и состояние хаотичны и непросты в обслуживании. пройти черезwindow.localStorage.getItem(key)получить данные пройти черезwindow.localStorage.setItem(key,value)Хранение данных

Обрати внимание наJSON.parse() / JSON.stringify()сделать преобразование формата данныхlocalStorage / sessionStorageможно комбинироватьvuex, Реализуйте постоянство данных и используйте vuex для решения проблемы путаницы данных и состояний.

Восемь$attrsа также$listeners

Теперь давайте обсудим ситуацию. На диаграмме отношений компонентов, которую мы дали в начале, компонент А и компонент D находятся в отношениях поколений. Каковы способы их общения раньше?

  1. использоватьpropsСвязывание для передачи информации с уровня на уровень, если изменение состояния в компоненте D необходимо для передачи данных в A, используйте систему событий, чтобы передать его уровень за уровнем.
  2. использоватьeventBus, его лучше использовать в этом случае, но когда дело доходит до совместной разработки с несколькими людьми, обслуживание кода низкое, а читабельность низкая.
  3. Используйте Vuex для управления данными, но если вы просто передаете данные без промежуточной обработки, использование обработки Vuex кажется излишним.

существуетvue2.4, чтобы удовлетворить это требование, введение$attrsа также$listeners, недавно добавленныйinheritAttrsопции. До версии 2.4 по умолчанию привязки атрибутов (кроме класса и стиля), которые не распознавались (и не извлекались) как реквизиты в родительской области, были «откатными» и применялись как обычные атрибуты HTML к дочерним компонентам корневого элемента. Давайте рассмотрим пример межуровневого общения:

// app.vue
// index.vue

<template>
  <div>
    <child-com1
      :name="name"
      :age="age"
      :gender="gender"
      :height="height"
      title="程序员成长指北"
    ></child-com1>
  </div>
</template>
<script>
const childCom1 = () => import("./childCom1.vue");
export default {
  components: { childCom1 },
  data() {
    return {
      name: "zhang",
      age: "18",
      gender: "女",
      height: "158"
    };
  }
};
</script>
// childCom1.vue

<template class="border">
  <div>
    <p>name: {{ name}}</p>
    <p>childCom1的$attrs: {{ $attrs }}</p>
    <child-com2 v-bind="$attrs"></child-com2>
  </div>
</template>
<script>
const childCom2 = () => import("./childCom2.vue");
export default {
  components: {
    childCom2
  },
  inheritAttrs: false, // 可以关闭自动挂载到组件根元素上的没有在props声明的属性
  props: {
    name: String // name作为props属性绑定
  },
  created() {
    console.log(this.$attrs);
     // { "age": "18", "gender": "女", "height": "158", "title": "程序员成长指北" }
  }
};
</script>
// childCom2.vue

<template>
  <div class="border">
    <p>age: {{ age}}</p>
    <p>childCom2: {{ $attrs }}</p>
  </div>
</template>
<script>

export default {
  inheritAttrs: false,
  props: {
    age: String
  },
  created() {
    console.log(this.$attrs); 
    // { "gender": "女", "height": "158", "title": "程序员成长指北" }
  }
};
</script>

Суммировать

Общие сценарии использования можно разделить на три категории:

  • Взаимодействие компонентов родитель-потомок:props; $parent / $children; provide / inject ; ref ; $attrs / $listeners
  • Связь компонентов Brother:eventBus ; vuex
  • Межуровневая коммуникация:eventBus;Векс;provide / inject,$attrs / $listeners

Так много, чем можно поделиться сегодня.Если вы заинтересованы в общем контенте, вы можете подписаться на официальную учетную запись «Руководство по развитию программиста» или присоединиться к группе технического обмена, чтобы обсудить его вместе.

Присоединяйтесь к нам, чтобы учиться вместе!