ΠŸΠ΅Ρ€Π΅ΠΉΡ‚ΠΈ ΠΊ основному содСрТимому

[Medium] πŸ“„ ΠšΠΎΠΌΠΌΡƒΠ½ΠΈΠΊΠ°Ρ†ΠΈΡ ΠΌΠ΅ΠΆΠ΄Ρƒ ΠΊΠΎΠΌΠΏΠΎΠ½Π΅Π½Ρ‚Π°ΠΌΠΈ

1. КакиС ΡΡƒΡ‰Π΅ΡΡ‚Π²ΡƒΡŽΡ‚ способы ΠΊΠΎΠΌΠΌΡƒΠ½ΠΈΠΊΠ°Ρ†ΠΈΠΈ ΠΌΠ΅ΠΆΠ΄Ρƒ Vue-ΠΊΠΎΠΌΠΏΠΎΠ½Π΅Π½Ρ‚Π°ΠΌΠΈ?​

КакиС ΠΏΠ°Ρ‚Ρ‚Π΅Ρ€Π½Ρ‹ ΠΊΠΎΠΌΠΌΡƒΠ½ΠΈΠΊΠ°Ρ†ΠΈΠΈ ΡΡƒΡ‰Π΅ΡΡ‚Π²ΡƒΡŽΡ‚ ΠΌΠ΅ΠΆΠ΄Ρƒ Vue-ΠΊΠΎΠΌΠΏΠΎΠ½Π΅Π½Ρ‚Π°ΠΌΠΈ?

БтратСгия ΠΊΠΎΠΌΠΌΡƒΠ½ΠΈΠΊΠ°Ρ†ΠΈΠΈ зависит ΠΎΡ‚ Ρ‚ΠΈΠΏΠ° ΠΎΡ‚Π½ΠΎΡˆΠ΅Π½ΠΈΠΉ ΠΌΠ΅ΠΆΠ΄Ρƒ ΠΊΠΎΠΌΠΏΠΎΠ½Π΅Π½Ρ‚Π°ΠΌΠΈ.

ΠšΠ°Ρ‚Π΅Π³ΠΎΡ€ΠΈΠΈ ΠΎΡ‚Π½ΠΎΡˆΠ΅Π½ΠΈΠΉβ€‹

Π ΠΎΠ΄ΠΈΡ‚Π΅Π»ΡŒ <-> Π”ΠΎΡ‡Π΅Ρ€Π½ΠΈΠΉ: props / emit / v-model / refs
ΠŸΡ€Π΅Π΄ΠΎΠΊ <-> ΠŸΠΎΡ‚ΠΎΠΌΠΎΠΊ: provide / inject
БосСдниС / нСсвязанныС ΠΊΠΎΠΌΠΏΠΎΠ½Π΅Π½Ρ‚Ρ‹: Pinia/Vuex (ΠΈΠ»ΠΈ event emitter для простых случаСв)

1. Props (Ρ€ΠΎΠ΄ΠΈΡ‚Π΅Π»ΡŒ β†’ Π΄ΠΎΡ‡Π΅Ρ€Π½ΠΈΠΉ)​

НазначСниС: Ρ€ΠΎΠ΄ΠΈΡ‚Π΅Π»ΡŒ ΠΏΠ΅Ρ€Π΅Π΄Π°Ρ‘Ρ‚ Π΄Π°Π½Π½Ρ‹Π΅ Π΄ΠΎΡ‡Π΅Ρ€Π½Π΅ΠΌΡƒ ΠΊΠΎΠΌΠΏΠΎΠ½Π΅Π½Ρ‚Ρƒ.

<!-- ParentComponent.vue -->
<template>
<div>
<h1>Π ΠΎΠ΄ΠΈΡ‚Π΅Π»ΡŒ</h1>
<ChildComponent
:message="parentMessage"
:user="userInfo"
:count="counter"
/>
</div>
</template>

<script setup>
import { ref } from 'vue';
import ChildComponent from './ChildComponent.vue';

const parentMessage = ref('ΠŸΡ€ΠΈΠ²Π΅Ρ‚ ΠΎΡ‚ родитСля');
const userInfo = ref({ name: 'John', age: 30 });
const counter = ref(0);
</script>
<!-- ChildComponent.vue -->
<template>
<div>
<h2>Π”ΠΎΡ‡Π΅Ρ€Π½ΠΈΠΉ</h2>
<p>Π‘ΠΎΠΎΠ±Ρ‰Π΅Π½ΠΈΠ΅: {{ message }}</p>
<p>ΠŸΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚Π΅Π»ΡŒ: {{ user.name }} ({{ user.age }})</p>
<p>Π‘Ρ‡Ρ‘Ρ‚Ρ‡ΠΈΠΊ: {{ count }}</p>
</div>
</template>

<script setup>
defineProps({
message: {
type: String,
required: true,
default: '',
},
user: {
type: Object,
required: true,
default: () => ({}),
},
count: {
type: Number,
default: 0,
validator: (value) => value >= 0,
},
});
</script>

ЗамСчания ΠΎ props​

  • Props ΡΠ²Π»ΡΡŽΡ‚ΡΡ ΠΎΠ΄Π½ΠΎΠ½Π°ΠΏΡ€Π°Π²Π»Π΅Π½Π½Ρ‹ΠΌΠΈ (источник истины β€” Ρ€ΠΎΠ΄ΠΈΡ‚Π΅Π»ΡŒ)
  • НС измСняйтС props Π½Π°ΠΏΡ€ΡΠΌΡƒΡŽ Π² Π΄ΠΎΡ‡Π΅Ρ€Π½Π΅ΠΌ ΠΊΠΎΠΌΠΏΠΎΠ½Π΅Π½Ρ‚Π΅
  • Если Π½ΡƒΠΆΠ½ΠΎ локальноС Ρ€Π΅Π΄Π°ΠΊΡ‚ΠΈΡ€ΠΎΠ²Π°Π½ΠΈΠ΅, скопируйтС Π·Π½Π°Ρ‡Π΅Π½ΠΈΠ΅ Π² Π»ΠΎΠΊΠ°Π»ΡŒΠ½Ρ‹ΠΉ ref
<script setup>
import { ref } from 'vue';

const props = defineProps({
message: String,
});

const localMessage = ref(props.message);
</script>

2. Emit (Π΄ΠΎΡ‡Π΅Ρ€Π½ΠΈΠΉ β†’ Ρ€ΠΎΠ΄ΠΈΡ‚Π΅Π»ΡŒ)​

НазначСниС: Π΄ΠΎΡ‡Π΅Ρ€Π½ΠΈΠΉ ΠΊΠΎΠΌΠΏΠΎΠ½Π΅Π½Ρ‚ увСдомляСт родитСля Ρ‡Π΅Ρ€Π΅Π· события.

<!-- ChildComponent.vue -->
<template>
<div>
<button @click="sendToParent">ΠžΡ‚ΠΏΡ€Π°Π²ΠΈΡ‚ΡŒ Ρ€ΠΎΠ΄ΠΈΡ‚Π΅Π»ΡŽ</button>
<input v-model="inputValue" @input="handleInput" />
</div>
</template>

<script setup>
import { ref } from 'vue';

const emit = defineEmits(['custom-event', 'update:modelValue']);
const inputValue = ref('');

const sendToParent = () => {
emit('custom-event', {
message: 'ΠŸΡ€ΠΈΠ²Π΅Ρ‚ ΠΎΡ‚ Π΄ΠΎΡ‡Π΅Ρ€Π½Π΅Π³ΠΎ ΠΊΠΎΠΌΠΏΠΎΠ½Π΅Π½Ρ‚Π°',
timestamp: Date.now(),
});
};

const handleInput = () => {
emit('update:modelValue', inputValue.value);
};
</script>
<!-- ParentComponent.vue -->
<template>
<div>
<h1>Π ΠΎΠ΄ΠΈΡ‚Π΅Π»ΡŒ</h1>
<ChildComponent
@custom-event="handleCustomEvent"
@update:modelValue="handleUpdate"
/>
<p>ΠŸΠΎΠ»ΡƒΡ‡Π΅Π½ΠΎ: {{ receivedData }}</p>
</div>
</template>

<script setup>
import { ref } from 'vue';
import ChildComponent from './ChildComponent.vue';

const receivedData = ref(null);

const handleCustomEvent = (data) => {
receivedData.value = data;
};

const handleUpdate = (value) => {
console.log('Π’Π²ΠΎΠ΄ ΠΎΠ±Π½ΠΎΠ²Π»Ρ‘Π½:', value);
};
</script>

Валидация emits Π² Vue 3​

<script setup>
const emit = defineEmits({
'custom-event': null,
'update:modelValue': (value) => {
if (typeof value !== 'string') {
console.warn('modelValue Π΄ΠΎΠ»ΠΆΠ΅Π½ Π±Ρ‹Ρ‚ΡŒ строкой');
return false;
}
return true;
},
});

emit('custom-event', 'data');
</script>

3. v-model (двусторонний ΠΊΠΎΠ½Ρ‚Ρ€Π°ΠΊΡ‚ Ρ€ΠΎΠ΄ΠΈΡ‚Π΅Π»ΡŒ-Π΄ΠΎΡ‡Π΅Ρ€Π½ΠΈΠΉ)​

Π‘Ρ‚ΠΈΠ»ΡŒ Vue 2​

<!-- Π ΠΎΠ΄ΠΈΡ‚Π΅Π»ΡŒ -->
<custom-input v-model="message" />
<!-- эквивалСнт -->
<custom-input :value="message" @input="message = $event" />
<!-- Π”ΠΎΡ‡Π΅Ρ€Π½ΠΈΠΉ Π² Vue 2 -->
<template>
<input :value="value" @input="$emit('input', $event.target.value)" />
</template>

<script>
export default {
props: ['value'],
};
</script>

Π‘Ρ‚ΠΈΠ»ΡŒ Vue 3​

<!-- Π ΠΎΠ΄ΠΈΡ‚Π΅Π»ΡŒ -->
<custom-input v-model="message" />
<!-- эквивалСнт -->
<custom-input :modelValue="message" @update:modelValue="message = $event" />
<!-- Π”ΠΎΡ‡Π΅Ρ€Π½ΠΈΠΉ Π² Vue 3 -->
<template>
<input :value="modelValue" @input="updateValue" />
</template>

<script setup>
defineProps({ modelValue: String });
const emit = defineEmits(['update:modelValue']);

const updateValue = (event) => {
emit('update:modelValue', event.target.value);
};
</script>

ΠœΠ½ΠΎΠΆΠ΅ΡΡ‚Π²Π΅Π½Π½Ρ‹Π΅ v-model Π² Vue 3​

<!-- Π ΠΎΠ΄ΠΈΡ‚Π΅Π»ΡŒ -->
<user-form v-model:name="userName" v-model:email="userEmail" />
<!-- Π”ΠΎΡ‡Π΅Ρ€Π½ΠΈΠΉ -->
<template>
<div>
<input
:value="name"
@input="$emit('update:name', $event.target.value)"
placeholder="Имя"
/>
<input
:value="email"
@input="$emit('update:email', $event.target.value)"
placeholder="Email"
/>
</div>
</template>

<script setup>
defineProps({
name: String,
email: String,
});
defineEmits(['update:name', 'update:email']);
</script>

4. Provide / Inject (ΠΏΡ€Π΅Π΄ΠΎΠΊ ↔ ΠΏΠΎΡ‚ΠΎΠΌΠΎΠΊ)​

НазначСниС: мСТуровнСвая коммуникация Π±Π΅Π· сквозной ΠΏΠ΅Ρ€Π΅Π΄Π°Ρ‡ΠΈ props.

<!-- GrandparentComponent.vue -->
<template>
<div>
<h1>ΠŸΡ€Π°Ρ€ΠΎΠ΄ΠΈΡ‚Π΅Π»ΡŒ</h1>
<parent-component />
</div>
</template>

<script setup>
import { ref, provide } from 'vue';

const userInfo = ref({ name: 'John', role: 'admin' });

const updateUser = (newInfo) => {
userInfo.value = { ...userInfo.value, ...newInfo };
};

provide('userInfo', userInfo);
provide('updateUser', updateUser);
</script>
<!-- ChildComponent.vue -->
<template>
<div>
<h3>Π”ΠΎΡ‡Π΅Ρ€Π½ΠΈΠΉ</h3>
<p>ΠŸΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚Π΅Π»ΡŒ: {{ userInfo.name }}</p>
<p>Роль: {{ userInfo.role }}</p>
<button @click="changeUser">ΠžΠ±Π½ΠΎΠ²ΠΈΡ‚ΡŒ ΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚Π΅Π»Ρ</button>
</div>
</template>

<script setup>
import { inject } from 'vue';

const userInfo = inject('userInfo');
const updateUser = inject('updateUser');

const changeUser = () => {
updateUser({ name: 'Jane', role: 'user' });
};
</script>

ЗамСчания ΠΎ Provide/Inject​

  • ΠžΡ‚Π»ΠΈΡ‡Π½ΠΎ ΠΏΠΎΠ΄Ρ…ΠΎΠ΄ΠΈΡ‚ для ΠΎΠ±Ρ‰Π΅Π³ΠΎ контСкста Π³Π»ΡƒΠ±ΠΎΠΊΠΎΠ³ΠΎ Π΄Π΅Ρ€Π΅Π²Π° (Ρ‚Π΅ΠΌΠ°/i18n/конфигурация)
  • МСнСС явный, Ρ‡Π΅ΠΌ props, поэтому Π²Π°ΠΆΠ½Ρ‹ ΠΈΠΌΠ΅Π½ΠΎΠ²Π°Π½ΠΈΠ΅ ΠΈ докумСнтация
  • РассмотритС использованиС readonly + явный API для ΠΌΡƒΡ‚Π°Ρ†ΠΈΠΉ
<script setup>
import { ref, readonly, provide } from 'vue';

const state = ref({ count: 0 });
provide('state', readonly(state));
provide('updateState', (newState) => {
state.value = newState;
});
</script>

5. Refs (Ρ€ΠΎΠ΄ΠΈΡ‚Π΅Π»ΡŒ Π½Π°ΠΏΡ€ΡΠΌΡƒΡŽ обращаСтся ΠΊ экзСмпляру Π΄ΠΎΡ‡Π΅Ρ€Π½Π΅Π³ΠΎ)​

НазначСниС: ΠΈΠΌΠΏΠ΅Ρ€Π°Ρ‚ΠΈΠ²Π½Ρ‹ΠΉ доступ (Π²Ρ‹Π·ΠΎΠ² ΠΎΡ‚ΠΊΡ€Ρ‹Ρ‚Ρ‹Ρ… ΠΌΠ΅Ρ‚ΠΎΠ΄ΠΎΠ² Π΄ΠΎΡ‡Π΅Ρ€Π½Π΅Π³ΠΎ ΠΊΠΎΠΌΠΏΠΎΠ½Π΅Π½Ρ‚Π°, Ρ‡Ρ‚Π΅Π½ΠΈΠ΅ ΠΎΡ‚ΠΊΡ€Ρ‹Ρ‚ΠΎΠ³ΠΎ состояния).

<!-- ParentComponent.vue -->
<template>
<child-component ref="childRef" />
<button @click="callChild">Π’Ρ‹Π·Π²Π°Ρ‚ΡŒ ΠΌΠ΅Ρ‚ΠΎΠ΄ Π΄ΠΎΡ‡Π΅Ρ€Π½Π΅Π³ΠΎ</button>
</template>

<script setup>
import { ref } from 'vue';
import ChildComponent from './ChildComponent.vue';

const childRef = ref(null);

const callChild = () => {
childRef.value.someMethod();
};
</script>

Π˜ΡΠΏΠΎΠ»ΡŒΠ·ΡƒΠΉΡ‚Π΅ с ΠΎΡΡ‚ΠΎΡ€ΠΎΠΆΠ½ΠΎΡΡ‚ΡŒΡŽ. Π‘Π½Π°Ρ‡Π°Π»Π° ΠΏΡ€Π΅Π΄ΠΏΠΎΡ‡ΠΈΡ‚Π°ΠΉΡ‚Π΅ Π΄Π΅ΠΊΠ»Π°Ρ€Π°Ρ‚ΠΈΠ²Π½Ρ‹ΠΉ ΠΏΠΎΡ‚ΠΎΠΊ Π΄Π°Π½Π½Ρ‹Ρ….

6. $parent / $root (Π½Π΅ рСкомСндуСтся)​

ΠŸΡ€ΡΠΌΠΎΠΉ доступ ΠΊ Ρ€ΠΎΠ΄ΠΈΡ‚Π΅Π»ΡŽ/ΠΊΠΎΡ€Π½ΡŽ ΡƒΠ²Π΅Π»ΠΈΡ‡ΠΈΠ²Π°Π΅Ρ‚ ΡΠ²ΡΠ·Π°Π½Π½ΠΎΡΡ‚ΡŒ ΠΈ услоТняСт отслСТиваниС ΠΏΠΎΡ‚ΠΎΠΊΠ° Π΄Π°Π½Π½Ρ‹Ρ…. ΠŸΡ€Π΅Π΄ΠΏΠΎΡ‡ΠΈΡ‚Π°ΠΉΡ‚Π΅ props/emit/provide ΠΈΠ»ΠΈ Ρ…Ρ€Π°Π½ΠΈΠ»ΠΈΡ‰Π΅.

7. Event Bus (ΡƒΡΡ‚Π°Ρ€Π΅Π²ΡˆΠΈΠΉ/простой pub-sub)​

Π’ Vue 2 часто использовался new Vue() ΠΊΠ°ΠΊ шина событий. Π’ Vue 3 ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΡƒΠΉΡ‚Π΅ нСбольшой эмиттСр, Π½Π°ΠΏΡ€ΠΈΠΌΠ΅Ρ€ mitt, Ρ‚ΠΎΠ»ΡŒΠΊΠΎ для Π»Ρ‘Π³ΠΊΠΈΡ… ΠΊΠ°Π½Π°Π»ΠΎΠ² событий.

// eventBus.js
import mitt from 'mitt';
export const emitter = mitt();
<!-- ComponentA.vue -->
<script setup>
import { emitter } from './eventBus';

const sendMessage = () => {
emitter.emit('message-sent', { text: 'ΠŸΡ€ΠΈΠ²Π΅Ρ‚', from: 'ComponentA' });
};
</script>
<!-- ComponentB.vue -->
<script setup>
import { onMounted, onUnmounted } from 'vue';
import { emitter } from './eventBus';

const handleMessage = (data) => {
console.log('ΠΏΠΎΠ»ΡƒΡ‡Π΅Π½ΠΎ:', data);
};

onMounted(() => emitter.on('message-sent', handleMessage));
onUnmounted(() => emitter.off('message-sent', handleMessage));
</script>

8. Vuex / Pinia (глобальноС ΡƒΠΏΡ€Π°Π²Π»Π΅Π½ΠΈΠ΅ состояниСм)​

НазначСниС: ΠΎΠ±Ρ‰Π΅Π΅ глобальноС состояниС для срСдних/ΠΊΡ€ΡƒΠΏΠ½Ρ‹Ρ… ΠΏΡ€ΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΠΉ.

Pinia β€” Ρ€Π΅ΠΊΠΎΠΌΠ΅Π½Π΄ΡƒΠ΅ΠΌΠΎΠ΅ Ρ€Π΅ΡˆΠ΅Π½ΠΈΠ΅ для Ρ…Ρ€Π°Π½ΠΈΠ»ΠΈΡ‰Π° Π² Vue 3.

// stores/user.js
import { defineStore } from 'pinia';

export const useUserStore = defineStore('user', {
state: () => ({
name: '',
email: '',
isLoggedIn: false,
}),
getters: {
fullInfo: (state) => `${state.name} (${state.email})`,
},
actions: {
login(name, email) {
this.name = name;
this.email = email;
this.isLoggedIn = true;
},
logout() {
this.name = '';
this.email = '';
this.isLoggedIn = false;
},
},
});

9. Slots (проСкция содСрТимого)​

НазначСниС: Ρ€ΠΎΠ΄ΠΈΡ‚Π΅Π»ΡŒ ΠΏΠ΅Ρ€Π΅Π΄Π°Ρ‘Ρ‚ шаблонноС содСрТимоС Π² ΠΎΠΏΡ€Π΅Π΄Π΅Π»Ρ‘Π½Π½Ρ‹Π΅ области Π΄ΠΎΡ‡Π΅Ρ€Π½Π΅Π³ΠΎ ΠΊΠΎΠΌΠΏΠΎΠ½Π΅Π½Ρ‚Π°.

Π‘Π°Π·ΠΎΠ²Ρ‹Π΅ слоты​

<!-- ChildComponent.vue -->
<template>
<div class="card">
<header>
<slot name="header">Π—Π°Π³ΠΎΠ»ΠΎΠ²ΠΎΠΊ ΠΏΠΎ ΡƒΠΌΠΎΠ»Ρ‡Π°Π½ΠΈΡŽ</slot>
</header>
<main>
<slot>Π‘ΠΎΠ΄Π΅Ρ€ΠΆΠΈΠΌΠΎΠ΅ ΠΏΠΎ ΡƒΠΌΠΎΠ»Ρ‡Π°Π½ΠΈΡŽ</slot>
</main>
<footer>
<slot name="footer"></slot>
</footer>
</div>
</template>
<!-- ParentComponent.vue -->
<template>
<child-component>
<template #header>
<h1>ΠŸΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚Π΅Π»ΡŒΡΠΊΠΈΠΉ Π·Π°Π³ΠΎΠ»ΠΎΠ²ΠΎΠΊ</h1>
</template>

<p>ОсновноС содСрТимоС</p>

<template #footer>
<button>ΠŸΠΎΠ΄Ρ‚Π²Π΅Ρ€Π΄ΠΈΡ‚ΡŒ</button>
</template>
</child-component>
</template>

Scoped slots (слоты с ΠΎΠ±Π»Π°ΡΡ‚ΡŒΡŽ видимости)​

<!-- ListComponent.vue -->
<template>
<ul>
<li v-for="(item, index) in items" :key="item.id">
<slot :item="item" :index="index"></slot>
</li>
</ul>
</template>

<script setup>
defineProps({ items: Array });
</script>
<!-- ParentComponent.vue -->
<template>
<list-component :items="users">
<template #default="{ item, index }">
<span>{{ index + 1 }}. {{ item.name }}</span>
</template>
</list-component>
</template>

Руководство ΠΏΠΎ Π²Ρ‹Π±ΠΎΡ€Ρƒ способа коммуникации​

ΠžΡ‚Π½ΠΎΡˆΠ΅Π½ΠΈΠ΅Π Π΅ΠΊΠΎΠΌΠ΅Π½Π΄ΡƒΠ΅ΠΌΡ‹ΠΉ ΠΏΠΎΠ΄Ρ…ΠΎΠ΄Π’ΠΈΠΏΠΈΡ‡Π½ΠΎΠ΅ использованиС
Π ΠΎΠ΄ΠΈΡ‚Π΅Π»ΡŒ β†’ Π”ΠΎΡ‡Π΅Ρ€Π½ΠΈΠΉPropsΠ’Ρ…ΠΎΠ΄Π½Ρ‹Π΅ Π΄Π°Π½Π½Ρ‹Π΅
Π”ΠΎΡ‡Π΅Ρ€Π½ΠΈΠΉ β†’ Π ΠΎΠ΄ΠΈΡ‚Π΅Π»ΡŒEmitΠžΠ±Ρ€Π°Ρ‚Π½Ρ‹ΠΉ Π²Ρ‹Π·ΠΎΠ² события
Π ΠΎΠ΄ΠΈΡ‚Π΅Π»ΡŒ ↔ Π”ΠΎΡ‡Π΅Ρ€Π½ΠΈΠΉv-modelБинхронизация Ρ„ΠΎΡ€ΠΌΡ‹
ΠŸΡ€Π΅Π΄ΠΎΠΊ β†’ ΠŸΠΎΡ‚ΠΎΠΌΠΎΠΊProvide/InjectΠ“Π»ΡƒΠ±ΠΎΠΊΠΈΠΉ контСкст Π΄Π΅Ρ€Π΅Π²Π°
Π ΠΎΠ΄ΠΈΡ‚Π΅Π»ΡŒ β†’ Π”ΠΎΡ‡Π΅Ρ€Π½ΠΈΠΉ (ΠΈΠΌΠΏΠ΅Ρ€Π°Ρ‚ΠΈΠ²Π½ΠΎ)RefsΠ Π΅Π΄ΠΊΠΈΠΉ прямой Π²Ρ‹Π·ΠΎΠ² ΠΌΠ΅Ρ‚ΠΎΠ΄Π°
Π›ΡŽΠ±Ρ‹Π΅ ΠΊΠΎΠΌΠΏΠΎΠ½Π΅Π½Ρ‚Ρ‹Pinia/VuexΠžΠ±Ρ‰Π΅Π΅ глобальноС состояниС
Π›ΡŽΠ±Ρ‹Π΅ ΠΊΠΎΠΌΠΏΠΎΠ½Π΅Π½Ρ‚Ρ‹ (просто)Event emitterΠ›Ρ‘Π³ΠΊΠΈΠΉ pub-sub
Π ΠΎΠ΄ΠΈΡ‚Π΅Π»ΡŒ β†’ Π”ΠΎΡ‡Π΅Ρ€Π½ΠΈΠΉ содСрТимоСSlotsΠšΠΎΠΌΠΏΠΎΠ·ΠΈΡ†ΠΈΡ шаблонов

ΠŸΡ€Π°ΠΊΡ‚ΠΈΡ‡Π΅ΡΠΊΠΈΠΉ ΠΏΡ€ΠΈΠΌΠ΅Ρ€: функция ΠΊΠΎΡ€Π·ΠΈΠ½Ρ‹ с Pinia​

// stores/cart.js
import { defineStore } from 'pinia';

export const useCartStore = defineStore('cart', {
state: () => ({
items: [],
}),
getters: {
totalPrice: (state) =>
state.items.reduce((sum, item) => sum + item.price * item.quantity, 0),
itemCount: (state) => state.items.length,
},
actions: {
addItem(product) {
const existing = this.items.find((item) => item.id === product.id);
if (existing) {
existing.quantity++;
} else {
this.items.push({ ...product, quantity: 1 });
}
},
removeItem(productId) {
const index = this.items.findIndex((item) => item.id === productId);
if (index > -1) this.items.splice(index, 1);
},
},
});

2. Π’ Ρ‡Ρ‘ΠΌ Ρ€Π°Π·Π½ΠΈΡ†Π° ΠΌΠ΅ΠΆΠ΄Ρƒ Props ΠΈ Provide/Inject?​

Π’ Ρ‡Ρ‘ΠΌ Ρ€Π°Π·Π½ΠΈΡ†Π° ΠΌΠ΅ΠΆΠ΄Ρƒ Props ΠΈ Provide/Inject?

Props​

Π₯арактСристики:

  • Π―Π²Π½Ρ‹ΠΉ ΠΈ Ρ‡Ρ‘Ρ‚ΠΊΠΈΠΉ ΠΏΠΎΡ‚ΠΎΠΊ Π΄Π°Π½Π½Ρ‹Ρ… Ρ€ΠΎΠ΄ΠΈΡ‚Π΅Π»ΡŒ-Π΄ΠΎΡ‡Π΅Ρ€Π½ΠΈΠΉ
  • Π‘ΠΎΠ»Π΅Π΅ строгоС ΠΎΠΏΡ€Π΅Π΄Π΅Π»Π΅Π½ΠΈΠ΅ Ρ‚ΠΈΠΏΠΎΠ²/ΠΊΠΎΠ½Ρ‚Ρ€Π°ΠΊΡ‚ΠΎΠ²
  • ΠžΡ‚Π»ΠΈΡ‡Π½ΠΎ ΠΏΠΎΠ΄Ρ…ΠΎΠ΄ΠΈΡ‚ для прямой ΠΊΠΎΠΌΠΌΡƒΠ½ΠΈΠΊΠ°Ρ†ΠΈΠΈ Ρ€ΠΎΠ΄ΠΈΡ‚Π΅Π»ΡŒ-Π΄ΠΎΡ‡Π΅Ρ€Π½ΠΈΠΉ
  • ΠœΠΎΠΆΠ΅Ρ‚ Π²Ρ‹Π·Ρ‹Π²Π°Ρ‚ΡŒ ΡΠΊΠ²ΠΎΠ·Π½ΡƒΡŽ ΠΏΠ΅Ρ€Π΅Π΄Π°Ρ‡Ρƒ props Ρ‡Π΅Ρ€Π΅Π· мноТСство ΡƒΡ€ΠΎΠ²Π½Π΅ΠΉ
<!-- сквозная ΠΏΠ΅Ρ€Π΅Π΄Π°Ρ‡Π° Ρ‡Π΅Ρ€Π΅Π· ΠΏΡ€ΠΎΠΌΠ΅ΠΆΡƒΡ‚ΠΎΡ‡Π½Ρ‹Π΅ ΠΊΠΎΠΌΠΏΠΎΠ½Π΅Π½Ρ‚Ρ‹ -->
<grandparent>
<parent :data="grandparentData">
<child :data="parentData">
<grandchild :data="childData" />
</child>
</parent>
</grandparent>

Provide/Inject​

Π₯арактСристики:

  • ΠžΡ‚Π»ΠΈΡ‡Π½ΠΎ ΠΏΠΎΠ΄Ρ…ΠΎΠ΄ΠΈΡ‚ для ΠΌΠ΅ΠΆΡƒΡ€ΠΎΠ²Π½Π΅Π²Ρ‹Ρ… зависимостСй
  • НС Π½ΡƒΠΆΠ½ΠΎ ΠΏΠ΅Ρ€Π΅Π΄Π°Π²Π°Ρ‚ΡŒ Ρ‡Π΅Ρ€Π΅Π· ΠΊΠ°ΠΆΠ΄Ρ‹ΠΉ ΠΏΡ€ΠΎΠΌΠ΅ΠΆΡƒΡ‚ΠΎΡ‡Π½Ρ‹ΠΉ слой
  • ΠŸΡ€ΠΈ Ρ‡Ρ€Π΅Π·ΠΌΠ΅Ρ€Π½ΠΎΠΌ использовании ΠΌΠ΅Π½Π΅Π΅ ΠΎΡ‡Π΅Π²ΠΈΠ΄Π΅Π½ источник Π΄Π°Π½Π½Ρ‹Ρ…
<grandparent> <!-- provide -->
<parent>
<child>
<grandchild /> <!-- inject -->
</child>
</parent>
</grandparent>

РСкомСндация​

  • Π˜ΡΠΏΠΎΠ»ΡŒΠ·ΡƒΠΉΡ‚Π΅ Props, ΠΊΠΎΠ³Π΄Π° Π²Π°ΠΆΠ½Π΅Π΅ всСго ΡΡΠ½ΠΎΡΡ‚ΡŒ ΠΏΠΎΡ‚ΠΎΠΊΠ° Π΄Π°Π½Π½Ρ‹Ρ… (особСнно Ρ€ΠΎΠ΄ΠΈΡ‚Π΅Π»ΡŒ-Π΄ΠΎΡ‡Π΅Ρ€Π½ΠΈΠΉ)
  • Π˜ΡΠΏΠΎΠ»ΡŒΠ·ΡƒΠΉΡ‚Π΅ Provide/Inject для Π³Π»ΡƒΠ±ΠΎΠΊΠΎΠ³ΠΎ ΠΎΠ±Ρ‰Π΅Π³ΠΎ контСкста (Ρ‚Π΅ΠΌΠ°, i18n, авторизация/конфигурация)
  • Для измСняСмого состояния всСго прилоТСния ΠΏΡ€Π΅Π΄ΠΏΠΎΡ‡ΠΈΡ‚Π°ΠΉΡ‚Π΅ Pinia/Vuex

Π‘ΠΏΡ€Π°Π²ΠΎΡ‡Π½Ρ‹Π΅ матСриалы​