דוגמת Vue: מספר מונים וצביעת הגדול ביותר בואו נכתוב תוכנית המציגה 4 מונים וצובעת את מונה הלחיצות שמראה את המספר הגדול ביותר בצבע שונה - וכן ננסה את זה ב Vue.
פיתרון 1 - שמירת כל המידע בקומפוננטה העליונה לכתוב מונה לחיצות ב Vue זה קל ובעצם אנחנו מקבלים כזה בחינם כשיוצרים פרויקט חדש. אבל אם נשים 4 קומפוננטות כאלה על המסך לא תהיה לנו דרך לתקשר בין 4 הקומפוננטות. כל אחת תספור לחיצות בצורה עצמאית ולא תדע מה מספר הלחיצות בקומפוננטות האחרות, ולכן לא ברור איך היא תדע להשתמש בצבע רקע שונה אם מספר הלחיצות אצלה הוא הגדול ביותר.
דרך אחת לחבר בין ארבעת הקומפוננטות היא ליצור קומפוננטה עוטפת ולהעביר את משתני ה ref של המונים לקומפוננטה העוטפת, בתור מערך. כל פעם שמשתמש לוחץ על כפתור באחת מקומפוננטות המונים אנחנו נעביר אירוע "נלחץ" לקומפוננטה העוטפת והיא כבר תעדכן את המספרים. הקומפוננטה העוטפת תוכל למצוא מה הערך הגדול ביותר ומי המונה עם הערך הגדול ביותר ולשמור את הערכים במשתני computed, וגם להעביר אותם פנימה לקומפוננטות המונים הפנימיות וכך קומפוננטת המונה עם הערך הגדול ביותר תוכל לצבוע את עצמה בירוק.
הקוד לקומפוננטה העוטפת הוא בסך הכל:
<script setup lang="ts">
import {ref, computed} from 'vue';
import Counter from './Counter.vue';
const counts = ref([0, 0, 0, 0]);
const maxValue = computed(() => Math.max(...counts.value));
const maxIndex = computed(() => counts.value.findIndex(el => el === maxValue.value));
function onClick(counterIndex) {
counts.value[counterIndex]++;
}
</script>
<template>
<p>max value = {{ maxValue }}</p>
<p>max index = {{ maxIndex }}</p>
<Counter @click="onClick(0)" :isMax="maxIndex == 0" :count="counts[0]"/>
<Counter @click="onClick(1)" :isMax="maxIndex == 1" :count="counts[1]"/>
<Counter @click="onClick(2)" :isMax="maxIndex == 2" :count="counts[2]"/>
<Counter @click="onClick(3)" :isMax="maxIndex == 3" :count="counts[3]"/>
</template>
ובגלל שכל המידע מנוהל בקומפוננטה זו קומפוננטות המונים יכולות להתמקד בהצגת המונה וב CSS לקביעת הצבע, והקוד של קומפוננטת המונה נראה כך:
<script setup lang="ts">
import { ref, computed } from 'vue'
const emit = defineEmits(['click']);
const {isMax, count} = defineProps<{isMax?: boolean, count: number}>();
const background = computed(() => isMax ? "green" : "yellow");
function onClick() {
emit('click');
}
</script>
<template>
<div>
<p>Value = {{ count }}</p>
<button @click="onClick">+1</button>
</div>
</template>
<style scoped>
div {
background-color: v-bind(background);
padding: 20px;
}
button {
color: white;
}
p {
color: black;
}
</style>
פיתרון 2 - שמירת המונים בכל קומפוננטה וערך המקסימום בקומפוננטה העליונה דרך אחרת לגשת לאותו אתגר היא לשים לב שהקומפוננטה העליונה בעצם לא עושה כלום עם ערכי המונים שהיא שומרת. כלומר כן היא צריכה את הערכים כדי להעביר אותם לקומפוננטות המונים, אבל המידע היחיד שמשותף לכל המונים זה הערך המקסימלי והאינדקס של הערך המקסימלי. לכן אפשר לארגן אחרת את הקוד ולהגדיר שכל מונה ידווח על אירוע כל פעם שהערך שלו מתעדכן. הקומפוננטה העוטפת תתפוס את האירוע ותבדוק - אם הערך החדש גדול יותר מהערך המקסימלי הנוכחי היא תשמור את הערך הזה בתור הערך המקסימלי החדש ותעדכן את המונה המקסימלי להיות המונה שזרק את האירוע. בכל מצב אחר אפשר להתעלם מהאירוע ולהמשיך הלאה.
בשביל הפיתרון אצטרך לספר לכם משהו נוסף לגבי אירועים - אירועים ב vue יכולים להישלח יחד עם פרמטר, והפרמטר מגיע לקוד הטיפול באירוע. מבחינת קוד זה די פשוט, הפונקציה emit יכולה לקבל פרמטר נוסף אחרי שם האירוע:
emit('change', 10);
ואפשר להעביר כמה פרמטרים שרוצים לפונקציה. בקוד הטיפול באירוע אנחנו מקבלים את הפרמטרים האלה בתור פרמטרים לפונקציה שמטפלת באירוע, או בכתיב החץ בתוך התבנית כלומר:
<Counter @change="(newValue) => doSomethingWith(newValue)" />
עכשיו שאנחנו יודעים את זה נוכל לכתוב את הקומפוננטה העוטפת ולקבל:
<script setup lang="ts">
import {ref} from 'vue';
import Counter from './Counter.vue';
const maxValue = ref<null|number>(null);
const maxIndex = ref<null|number>(null);
function onNewValue(counterIndex, value) {