1212 способов взаимодействия между родительскими и дочерними компонентами в Vue.js

Vue.js

Интервьюер: Каковы способы взаимодействия между родительскими и дочерними компонентами в Vue?

Подумайте минуту.

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

В последнее время я занимаюсь оптимизацией на уровне кода проекта Vue.Если честно, оптимизация чужого кода - дело действительно болезненное.Не будем говорить о реализации функции, но про спецификацию кода я могу написать еще одну статью. Без норм создать кружок действительно невозможно, слишком важно регламентировать это дело! Это немного разглагольствования, вернемся к теме, кашель, давайте поговорим о моем понимании вопросов интервью выше, написание ограничено, и если есть что-то неуместное, пожалуйста, оставьте сообщение в конце статьи.

список

Несколько способов связи представляют собой не что иное, как следующее:

  • Prop(обычно используется)
  • $emit(Подробнее об упаковке компонентов)
  • .syncсинтаксический сахар (меньше)
  • $attrs & $listeners(Подробнее об упаковке компонентов)
  • provide & inject(Компоненты/библиотеки компонентов более высокого порядка используются чаще)
  • slot-scope & v-slot(vue@2.6.0+) новый
  • scopedSlotsАтрибуты
  • другие средства связи

Давайте представим их по одному, Боже, пожалуйста, в обход.

1. Prop

Британское произношение: [prɒp]. Это часто используется в нашей повседневной разработке. Проще говоря,мы можем пройтиPropПередать данные дочерним компонентам. Если использовать образную метафору, передача данных между родительским и дочерним компонентами эквивалентна нисходящей канализационной трубе, которая может течь только сверху вниз, но не в обратном направлении. Это также часть философии дизайна Vue.Однонаправленный поток данных. А Prop — это связь между трубами и трубами, чтобы вода (данные) могла стекать вниз. Сказав все это, посмотрите на код:

<div id="app">
  <child :content="message"></child>
</div>
// Js
let Child = Vue.extend({
  template: '<h2>{{ content }}</h2>',
  props: {
    content: {
      type: String,
      default: () => { return 'from child' }
    }
  }
})

new Vue({
  el: '#app',
  data: {
    message: 'from parent'
  },
  components: {
    Child
  }
})

ты можешь быть жесткимкликните сюдаПроверьте демо! Вывод браузера:

from parent

2. $emit

Британское произношение: [iˈmɪt]. Официальное заявлениеЗапускает событие в текущем экземпляре. Дополнительные параметры передаются обратному вызову слушателя.. Насколько я понимаю, я не знаю, смогу ли я объяснить это вам.Давайте сначала кратко рассмотрим код:

<div id="app">
  <my-button @greet="sayHi"></my-button>
</div>
let MyButton = Vue.extend({
  template: '<button @click="triggerClick">click</button>',
  data () {
    return {
      greeting: 'vue.js!'
    }
  },
  methods: {
    triggerClick () {
      this.$emit('greet', this.greeting)
    }
  }
})

new Vue({
  el: '#app',
  components: {
    MyButton
  },
  methods: {
    sayHi (val) {
      alert('Hi, ' + val) // 'Hi, vue.js!'
    }
  }
})

ты можешь быть жесткимкликните сюдаПроверьте демо!Общая логика - это соус: когда я нажимаю кнопку на странице, компонент срабатываетMyButtonпрослушать событие наgreetи передать параметры функции обратного вызоваsayHi. Грубо говоря, когда мы начинаем с дочернего компонентаEmit(Отправка) Перед событием его внутренняя часть продвигается в очереди событий.On(прослушивается) это событие и его обратный вызов слушателя. Фактически, это эквивалентно следующему письму:

vm.$on('greet', function sayHi (val) {
  console.log('Hi, ' + val)
})
vm.$emit('greet', 'vue.js')
// => "Hi, vue.js"

3. модификатор .sync

Этот парень существовал как функция двусторонней привязки, когда vue@1.x, то есть дочерний компонент мог изменять значение в родительском компоненте. потому что это нарушаетОднонаправленный поток данныхКонцепция дизайна, поэтому она была убита, когда vue@2.0. Но это было повторно введено в vue@2.3.0+ и выше..syncмодификатор. Но на этот раз он существует только как синтаксический сахар времени компиляции. Он будет расширен до прослушивателя v-on, который автоматически обновляет свойства родительского компонента. Грубо говоря, давайте вручную обновим значение в родительском компоненте, чтобы источник изменения данных был более очевиден. Ниже приводится выдержка из официального пассажа:

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

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

<text-document
  v-bind:title="doc.title"
  v-on:update:title="doc.title = $event">
</text-document>

Таким образом, мы можем использовать.syncСинтаксический сахар сокращен следующим образом:

<text-document v-bind:title.sync="doc.title"></text-document>

Столько ерунды, как добиться "двусторонней привязки"? Перейдем к рекламе, а после рекламы еще интереснее! ... Хорошо, с возвращением. Предположим, мы хотим добиться такого эффекта: изменение значения в текстовом поле дочернего компонента также меняет значение в родительском компоненте. Как это сделать? Ранк может сначала подумать. Сначала посмотрите на код:

<div id="app">
  <login :name.sync="userName"></login> {{ userName }}
</div>
let Login = Vue.extend({
  template: `
    <div class="input-group">
      <label>姓名:</label>
      <input v-model="text">
    </div>
  `,
  props: ['name'],
  data () {
    return {
      text: ''
    }
  },
  watch: {
    text (newVal) {
      this.$emit('update:name', newVal)
    }
  }
})

new Vue({
  el: '#app',
  data: {
    userName: ''
  },
  components: {
    Login
  }
})

ты можешь быть жесткимкликните сюдаПосмотрите демо! Подчеркните ключевые моменты, в коде есть такое предложение:

this.$emit('update:name', newVal)

Официальный синтаксис:update:myPropNameвmyPropNameПредставляет значение реквизита для обновления. Конечно, если вы используете .$emit выше без синтаксического сахара .sync, вы можете добиться того же эффекта. Это все!

4. $attrs & $listeners

  • Официальный сайт$attrsобъясняется следующим образом:

Содержит привязки свойств, которые не распознаются (и не получены) как свойства в родительской области (classа такжеstyleКроме). Когда компонент не объявляет никаких реквизитов, сюда включаются все привязки родительской области (classа такжеstyleкроме), и может пройтиv-bind="$attrs"Передача внутренних компонентов — полезно при создании высокоуровневых компонентов.

  • Официальный сайт$listenersобъясняется следующим образом:

Входит в родительскую область (исключая.nativeмодификатор)v-onпрослушиватель событий. это может пройтиv-on="$listeners"Передача внутренних компонентов — полезно при создании компонентов более высокого уровня.

я думаю$attrsа также$listenersАтрибуты похожи на два ящика для хранения, один отвечает за хранение атрибутов, а другой отвечает за хранение событий, оба из которых хранятся в виде объектов. См. объяснение кода ниже:

<div id="app">
  <child 
    :foo="foo" 
    :bar="bar"
    @one.native="triggerOne"
    @two="triggerTwo">
  </child>
</div>

Как видно из Html, есть два свойства и два метода, разница в том, что одно из свойствpropобъявляет, что событие один.nativeмодификатор.

let Child = Vue.extend({
  template: '<h2>{{ foo }}</h2>',
  props: ['foo'],
  created () {
    console.log(this.$attrs, this.$listeners)
    // -> {bar: "parent bar"}
    // -> {two: fn}
    
    // 这里我们访问父组件中的 `triggerTwo` 方法
    this.$listeners.two()
    // -> 'two'
  }
})

new Vue({
  el: '#app',
  data: {
    foo: 'parent foo',
    bar: 'parent bar'
  },
  components: {
    Child
  },
  methods: {
    triggerOne () {
      alert('one')
    },
    triggerTwo () {
      alert('two')
    }
  }
})

ты можешь быть жесткимкликните сюдаПосмотреть демо! Вы можете увидеть, мы можем$attrsа также$listenersОчень удобно передавать данные, звонить и обрабатывать там, где нужно. Конечно, мы также можемv-on="$listeners"Он передается уровень за уровнем, и потомки бесконечны!

Интерлюдия!

Когда мы назначаем компоненту не-Prop объявление, скомпилированный код будет рассматривать эти атрибуты как исходные атрибуты и добавлять их в нативный тег html. Посмотрите, как приведенный выше код выглядит после компиляции:

<h2 bar="parent bar">parent foo</h2>

Это было бы некрасиво, и это бы что-то взорвало. Как избавиться от этого? это точноinheritAttrsАрена недвижимости! Добавьте это свойство на компонент на линии, обычно с$attrsиспользовать. Посмотрите на код:

// 源码
let Child = Vue.extend({
  ...
  inheritAttrs: false, // 默认是 true
  ...
})

Скомпилируйте снова:

<h2>parent foo</h2>

5. provide & inject

Они вдвоем против КП и чувствуют себя довольно загадочно. Взгляните на официальнуюprovide / injectописание:

provideа такжеinjectВ основном предоставляет варианты использования для библиотек плагинов/компонентов более высокого порядка. Его не рекомендуется использовать непосредственно в коде приложения. И эту пару опций необходимо использовать вместе, чтобы позволить компоненту-предку внедрить зависимость во все его потомки, независимо от того, насколько глубока иерархия компонентов, и это всегда будет действовать, пока устанавливаются отношения восходящего и нисходящего потоков.

看完描述有点懵懵懂懂! Sentence summary is this: Your father a child everything to help you keep waiting for you to grow up with the young married woman you want to marry you buy a house you want to buy a car for as long as he will try to meet some of ты.下面是这句话的代码解释:

<div id="app">
  <son></son>
</div>
let Son = Vue.extend({
  template: '<h2>son</h2>',
  inject: {
    house: {
      default: '没房'
    },
    car: {
      default: '没车'
    },
    money: {
      // 长大工作了虽然有点钱
      // 仅供生活费,需要向父母要
      default: '¥4500'
    }
  },
  created () {
    console.log(this.house, this.car, this.money)
    // -> '房子', '车子', '¥10000'
  }
})

new Vue({
  el: '#app',
  provide: {
    house: '房子',
    car: '车子',
    money: '¥10000'
  },
  components: {
    Son
  }
})

ты можешь быть жесткимкликните сюдаПроверьте демо!

6. slot-scope & v-slot

Для ознакомления с этим подходом см. мое введение к этой статье.Портал ->

7. scopedSlotsАтрибуты

Для ознакомления с этим подходом см. мое введение к этой статье.Портал ->

8. Другие средства связи

Помимо вышеперечисленных пяти методов, на самом деле существуют:

  • EventBus

Идея состоит в том, чтобы объявить глобальную переменную экземпляра Vue.EventBus, Храните все данные связи и прослушиватели событий в этой переменной. может читатьСвязь между компонентами Vue с использованием шины событийпонять больше. Таким образом достигается обмен данными между компонентами, что несколько похоже наVuex. Но этот метод подходит только для очень маленьких проектов, а Vuex по-прежнему рекомендуется для сложных проектов. Вот простой код для реализации EventBus:

<div id="app">
  <child></child>
</div>
// 全局变量
let EventBus = new Vue()

// 子组件
let Child = Vue.extend({
  template: '<h2>child</h2>',
  created () {
    console.log(EventBus.message)
    // -> 'hello'
    EventBus.$emit('received', 'from child')
  }
})

new Vue({
  el: '#app',
  components: {
    Child
  },
  created () {
    // 变量保存
    EventBus.message = 'hello'
    // 事件监听
    EventBus.$on('received', function (val) {
      console.log('received: '+ val)
      // -> 'received: from child'
    })
  }
})

ты можешь быть жесткимкликните сюдаПроверьте демо!

  • Vuex

Официально рекомендуемый режим Vuex — это режим управления состоянием, специально разработанный для приложений Vue.js.

  • $parent

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

  • $root

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

  • broadcast / dispatch

Это методы в vue @1.0, которые являются вещанием событий и отправка событий. Хотя Vue@2.0 был удален, эти два метода могут быть смоделированы. может учиться из-заElementвыполнить. Иногда это все еще очень полезно, например, когда мы разрабатываем сборку дерева и т. д.

Суммировать

Сказав так много, я надеюсь, что одноклассники, которые это увидят, приобретут больше или меньше. Пожалуйста, оставьте сообщение, чтобы исправить неправильное место, большое спасибо. На самом деле существует много видов связи между родительскими и дочерними компонентами, в зависимости от обстоятельств, в которых вы их используете. Различные сценарии трактуются по-разному. Суть в том, что вы должны знать, что делать! До Великого Бога еще далеко, пока вы каждый день смотрите на сообщество, просматриваете документацию, пишете демки и каждый день добиваетесь небольшого прогресса, успехи всегда будут. Как говорится,У трех человек должен быть мой учитель, Я надеюсь, что больше друзей-единомышленников смогут собраться вместе, чтобы обменяться технологиями! Следующая группа почти заполнена, вы можете добавить меняQ1769617251. Обратите внимание, что vue достаточно.