Я объясню различия в совместном использовании данных между API-интерфейсом option и API-интерфейсом композиции. Также продемонстрирую потенциальные способы использования API-интерфейса композиции для обмена данными от дочернего компонента к родительскому компоненту, например испускание и предоставление.

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

<script setup>
//composition api with setup script
// any property or methods are private 
import { ref } from 'vue'
const name= ref("child component");
const increase =()=>{
  return count.value = count.value + 1;
} 
</script>

Но если вы создаете компонент с помощью option API, свойства и методы этого дочернего компонента будут общедоступными. Таким образом, родительский компонент может получить доступ к свойствам и методам дочерних компонентов, используя этот экземпляр компонента или цепочки $parent.

<script>
// any property or method are public
//accessible from parent 
export default {
    data() {
        return {
            name: '',
        }
    },
    methods: {
         increase() {
         return this.count = this.count + 1;
        },   
    },
    
}
</script>

Существует два способа передачи данных от дочернего компонента к родительскому с помощью API композиции с настройкой сценария.

  1. defineExpose
  2. Создать событие

defineExpose:метод defineExpose позволяет компоненту предоставлять свои методы и свойства общедоступным для родительского компонента.

Чтобы обеспечить передачу данных между дочерним компонентом в родительский с использованием API композиции с defineExpose, вам необходимо выполнить два шага.

Шаг 1: используйте метод defineExposeв дочернем компоненте, чтобы предоставить свойства и методы.

defineExpose()

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

//ChildComponent.vue

<script setup>
import { ref, defineExpose } from "vue";

const name = ref("child component");
const count = ref(1);
const isAdult = ref(false);
const age = ref(17);


const increase = () => {
  count.value = count.value + 1;
  isAdult.value = count.value > age.value;
};

const decrease = () => {
  if (count.value > 0) count.value = count.value - 1;
  isAdult.value = count.value > age.value;
};

//age is private
//rest of the properties & methods are public
defineExpose({
  name,
  count,
  isAdult,
  increase,
  decrease,
});
</script>

<template>
  <h5>Child To Parent Data passing</h5>
</template>

Шаг 2. В родительский компонент вам необходимо добавить дочерний компонент. Теперь вам нужно создать экземпляр дочернего компонента.

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

Здесь я добавил ChildComponent.vue в родительский компонент. Я также создал экземпляр n с именем child из ChildComponent.vue. Используя этот экземпляр, я получил доступ к общедоступным свойствам name, isAdult и count, а также к методам увеличения и уменьшения.

//ParentComponent.vue

<script setup>
import ChildComponent from "./ChildComponent.vue";
import { ref, onMounted, computed } from "vue";

const child = ref(null);
const childComponetName = ref("");

const onChildIncrement = () => {
  child.value.increase();
  //increase child count
};

const onChildDecrement = () => {
  child.value.decrease();
  //decrease child count
};

onMounted(() => {
  childComponetName.value = child.value.name;
  // child components name is not updating
  //so i have read it after initial render
});

const childComponetCount = computed(() => {
  return child.value?.count;
  // if child count update it will return the latest count;
});
const isParentsChildAdult = computed(() => {
  return child.value?.isAdult;
  // if child isAdult update it will return the latest isAdult;
});
</script>

<template>
  <div>
    <ChildComponent ref="child" />
    
    <p>Count:{{ childComponetCount }}</p>
    <p>Adult child? {{ isParentsChildAdult }}</p>

    <div class="btn">
      <button type="button" @click="onChildDecrement">decrement</button>
      <button type="button" @click="onChildIncrement">increment</button>
    </div>
  </div>
</template>

<style scoped>
.btn {
  display: flex;
  justify-content: center;
  gap: 20px;
}
</style>

Emit Event:используяметодmit, вы можете создать собственное событиеt и передавать данные из дочерний элемент родительского компонента/прослушивающего компонента. Всякий раз, когда дочерний компонент запускает событие, прослушивающий/родительский компонент будет прослушивать это событие и действовать соответствующим образом.

Методы Emit принимают уникальное имя события и данные события. Вы можете игнорировать данные о событии, но имя события является обязательным.

emit('customEventName', eventData);
         or
emit('customEventName');
//customEventName must be unique

Чтобы обеспечить передачу данных между дочерним компонентом в родительский с помощью API композиции с emite, вам необходимо выполнить два шага.

Шаг 1:Создайте пользовательское событие с отправкой в ​​дочернем компоненте. Вы можете создавать пользовательские события из шаблона вашего компонента. >или раздел сценария.

Раздел скрипта: если вы используете submit с настройкой скрипта, вы должны объявить пользовательские события непосредственно в defineEmits. Здесь я объявил как handleIncrease, так и handleDecrease. > события в defineEmits. Позже я создал эти события и передал свойства как данные событий.

<script setup>
import { defineEmits, ref } from "vue";

//list of declared custom events
const emit = defineEmits(["handleIncrease", "handleDecrease"]);

const count = ref(1);
const age = ref(17);


const increase = () => {
  count.value = count.value + 1;
  const isAdult = count.value > age.value;
  emit("handleIncrease", count.value, isAdult);
 //custom event with event data
};
//
const decrease = () => {
  if (count.value > 0) count.value = count.value - 1;
  const isAdult = count.value > age.value;
  emit("handleDecrease", count.value, isAdult);
//custom event with event data
};
</script>

Раздел шаблона. Для встроенного излучения вам не нужно объявлять какие-либо пользовательские события. Вот почему я создал непосредственное встроенное getSearchInputсобытие из шаблонов и передал значение поиска в качестве данных события.

<script setup>
import {ref } from "vue";
const search = ref("");
</script>

<template>
  <input
      type="text"
      class="form-control"
      v-model="search"
      @input="$emit('getSearchInput', search)" />
  
</template>

<style scoped>
.form-control {
  margin: 10px;
}

</style>

Рассматривая оба случая, завершите код дочернего компонента с помощью Emit:

//ChildComponent.vue
<script setup>
import { defineEmits, ref } from "vue";

//list of declared custom events
const emit = defineEmits(["handleIncrease", "handleDecrease"]);

const count = ref(1);
const age = ref(17);
const search = ref("");

const increase = () => {
  count.value = count.value + 1;
  const isAdult = count.value > age.value;
  emit("handleIncrease", count.value, isAdult);
  //custom event with event data
};
//
const decrease = () => {
  if (count.value > 0) count.value = count.value - 1;
  const isAdult = count.value > age.value;
  emit("handleDecrease", count.value, isAdult);
  //custom event with event data
};
</script>

<template>
  <div class="btn">
    <button type="button" @click="decrease">decrement</button>
    <button type="button" @click="increase">increment</button>
  </div>

  <!-- Inline emit getSearchInput & searchValue is passing as argument-->
  <input
    type="text"
    class="form-control"
    v-model="search"
    @input="$emit('getSearchInput',search)"
  />
</template>

<style scoped>
.form-control {
  margin: 10px;
}
.btn {
  display: flex;
  justify-content: center;
  gap: 20px;
}
</style>

Шаг 2. В родительский/прослушивающий компонент вам необходимо добавить дочерний компонент. Теперь вам нужно связать эти пользовательские события в шаблонах Vue.js, используя директиву on или ее сокращенный символ @.

Итак, я добавил ChildComponent.vue в ParentComponent.vue и привязал все три пользовательских события.

//ParentComponent.vue
<script setup>

import ChildComponent from "./ChildComponent.vue";
import { ref } from "vue";
const parentCount = ref(1);
const isParentsChildAdult = ref(false);

const increaseParent = (childCount, isAdult) => {
  parentCount.value = childCount;
  isParentsChildAdult.value = isAdult;
 //Whenever in child component user click increase method,
 //handleIncrease event will listen and act accordingly
};

const decreaseParent = (childCount, isAdult) => {
  parentCount.value = childCount;
  isParentsChildAdult.value = isAdult;
 //Whenever in child component user click descrease method,
 //handleDecrease event will listen and act accordingly

};

const showAlert = (value) => {
  alert(value);
 //Whenever in child component user fills input ,
 //getSearchInput event  will listen 
 
};
</script>

<template>
  <p>{{ parentCount }}</p>
  <p>Adult child? {{ isParentsChildAdult }}</p>
  <ChildComponent
    @handleIncrease="increaseParent"
    @handleDecrease="decreaseParent"
    @getSearchInput="showAlert" />
</template>


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