İletişim türleri
Bir Vue uygulaması (veya aslında herhangi bir bileşen tabanlı uygulama) tasarlarken, hangi endişelerle uğraştığımıza bağlı olarak farklı iletişim türleri vardır ve bunların kendi iletişim kanalları vardır.
İş mantığı: Uygulamanıza ve amacına özgü her şeyi ifade eder.
Sunum mantığı: Kullanıcının etkileşim kurduğu veya kullanıcının etkileşiminden kaynaklanan her şey.
Bu iki endişe, bu tür iletişimlerle ilgilidir:
- Uygulama durumu
- Ebeveyn-çocuk
- Çocuk ebeveyn
- Kardeşler
Her tür doğru iletişim kanalını kullanmalıdır.
İletişim kanalları
Kanal, bir Vue uygulaması etrafında veri alışverişi yapmak için somut uygulamalara atıfta bulunmak için kullanacağım gevşek bir terimdir.
Destekler: Ebeveyn-Çocuk sunum mantığı
Doğrudan Ebeveyn-Çocuk iletişimi için Vue'daki en basit iletişim kanalı . Çoğunlukla sunum mantığıyla veya sınırlı bir veri kümesiyle ilgili verileri hiyerarşinin altına aktarmak için kullanılmalıdır.
Referanslar ve yöntemler: Sunum anti-model
Bir çocuğun bir ebeveynden gelen bir olayı işlemesine izin vermek için bir pervane kullanmak mantıklı olmadığında , alt bileşen üzerinde bir ref
öğe oluşturmak ve onun yöntemlerini çağırmak gayet iyi.
Bunu yapma, bu bir anti-modeldir. Bileşen mimarinizi ve veri akışınızı yeniden düşünün. Kendinizi bir ebeveynden bir alt bileşende bir yöntem çağırmak isterken bulursanız, muhtemelen durumu yükseltmenin veya burada veya diğer cevaplarda açıklanan diğer yolları düşünmenin zamanı gelmiştir .
Olaylar: Alt-Üst sunum mantığı
$emit
ve $on
. Doğrudan Çocuk-Ebeveyn iletişimi için en basit iletişim kanalı. Yine sunum mantığı için kullanılmalıdır.
Etkinlik veriyolu
Yanıtların çoğu, uzak bileşenler veya aslında herhangi bir şey için mevcut iletişim kanallarından biri olan olay veri yolu için iyi alternatifler sunar.
Bu, sahne donanımlarını çok yukarıdan derinlemesine iç içe geçmiş alt bileşenlere geçirirken, aralarında neredeyse hiçbir bileşene ihtiyaç duymadan, yararlı olabilir. Dikkatlice seçilmiş veriler için idareli kullanın.
Dikkatli olun: Kendilerini olay veri yoluna bağlayan bileşenlerin daha sonra oluşturulması birden fazla kez bağlanacaktır - bu da birden çok işleyicinin tetiklenmesine ve sızıntılara neden olur. Geçmişte tasarladığım tüm tek sayfalık uygulamalarda kişisel olarak bir etkinlik otobüsüne ihtiyaç duymadım.
Aşağıdaki, basit bir hatanın, Item
bileşenin DOM'dan kaldırılsa bile hala tetiklendiği bir sızıntıya nasıl yol açtığını göstermektedir .
// A component that binds to a custom 'update' event.
var Item = {
template: `<li>{{text}}</li>`,
props: {
text: Number
},
mounted() {
this.$root.$on('update', () => {
console.log(this.text, 'is still alive');
});
},
};
// Component that emits events
var List = new Vue({
el: '#app',
components: {
Item
},
data: {
items: [1, 2, 3, 4]
},
updated() {
this.$root.$emit('update');
},
methods: {
onRemove() {
console.log('slice');
this.items = this.items.slice(0, -1);
}
}
});
<script src="https://unpkg.com/vue@2.5.17/dist/vue.min.js"></script>
<div id="app">
<button type="button" @click="onRemove">Remove</button>
<ul>
<item v-for="item in items" :key="item" :text="item"></item>
</ul>
</div>
destroyed
Yaşam döngüsü kancasından dinleyicileri çıkarmayı unutmayın .
Merkezi mağaza (İş mantığı)
Vuex , durum yönetimi için Vue ile gitmenin yoludur . Olaylardan çok daha fazlasını sunar ve tam ölçekli uygulama için hazırdır.
Ve şimdi soruyorsun :
[S] Her küçük iletişim için vuex'in deposunu oluşturmalı mıyım?
Gerçekten ne zaman parlıyor:
- iş mantığınızla ilgilenmek,
- bir arka uçla (veya yerel depolama gibi herhangi bir veri kalıcılığı katmanıyla) iletişim kurma
Böylece bileşenleriniz gerçekten olması gereken şeylere, yani kullanıcı arayüzlerini yönetmeye odaklanabilir.
Bu, onu bileşen mantığı için kullanamayacağınız anlamına gelmez, ancak bu mantığı yalnızca gerekli global UI durumuna sahip ad alanlı bir Vuex modülüne dahil edeceğim.
Küresel bir durumda her şeyin büyük bir karmaşasıyla uğraşmaktan kaçınmak için, mağaza birden çok ad alanlı modülde ayrılmalıdır.
Bileşen türleri
Tüm bu iletişimi düzenlemek ve yeniden kullanılabilirliği kolaylaştırmak için bileşenleri iki farklı tür olarak düşünmeliyiz.
- Uygulamaya özel kapsayıcılar
- Genel bileşenler
Yine, genel bir bileşenin yeniden kullanılması gerektiği veya uygulamaya özel bir kapsayıcının yeniden kullanılamayacağı anlamına gelmez, ancak farklı sorumlulukları vardır.
Uygulamaya özel kapsayıcılar
Bunlar, diğer Vue bileşenlerini (jenerik veya diğer uygulamaya özel kapsayıcılar) saran basit bir Vue bileşenidir. Bu, Vuex mağaza iletişiminin gerçekleşmesi gereken yerdir ve bu kapsayıcı, sahne donanımı ve olay dinleyicileri gibi diğer daha basit yollarla iletişim kurmalıdır.
Bu kapsayıcıların hiçbir yerel DOM öğesi bile olmayabilir ve genel bileşenlerin şablon oluşturma ve kullanıcı etkileşimleriyle ilgilenmesine izin verebilir.
kardeş bileşenleri için bir şekilde kapsamevents
veya stores
görünürlük
Kapsam belirleme burada gerçekleşir. En bileşenleri mağaza hakkında bilgi yoktur ve bu bileşen (çoğunlukla) kullanılması, bir sınırlı bir dizi mağaza modülü alanlı olmalıdır getters
ve actions
Resim uygulanan Vuex bağlanma yardımcıları .
Genel bileşenler
Bunlar verilerini sahne donanımlarından almalı, kendi yerel verilerinde değişiklik yapmalı ve basit olaylar yaymalıdır. Çoğu zaman, bir Vuex mağazasının var olduğunu bilmemelidirler.
Tek sorumlulukları diğer UI bileşenlerine göndermek olabileceğinden bunlara konteyner de denilebilir.
Kardeş iletişimi
Öyleyse, tüm bunlardan sonra, iki kardeş bileşen arasında nasıl iletişim kurmalıyız?
Bir örnekle anlaşılması daha kolay: Bir giriş kutumuz olduğunu ve verilerinin uygulama genelinde paylaşılması (ağaçta farklı yerlerdeki kardeşler) ve bir arka uç ile kalıcı olması gerektiğini söyleyin.
En kötü durum senaryosundan başlayarak , bileşenimiz sunum ve iş mantığını karıştıracaktır .
// MyInput.vue
<template>
<div class="my-input">
<label>Data</label>
<input type="text"
:value="value"
:input="onChange($event.target.value)">
</div>
</template>
<script>
import axios from 'axios';
export default {
data() {
return {
value: "",
};
},
mounted() {
this.$root.$on('sync', data => {
this.value = data.myServerValue;
});
},
methods: {
onChange(value) {
this.value = value;
axios.post('http://example.com/api/update', {
myServerValue: value
})
.then((response) => {
this.$root.$emit('update', response.data);
});
}
}
}
</script>
Bu iki endişeyi ayırmak için, bileşenimizi uygulamaya özel bir kapsayıcıya sarmalı ve sunum mantığını genel girdi bileşenimizde tutmalıyız.
Girdi bileşenimiz artık yeniden kullanılabilir ve arka uç veya kardeşler hakkında bilgi sahibi değildir.
// MyInput.vue
// the template is the same as above
<script>
export default {
props: {
initial: {
type: String,
default: ""
}
},
data() {
return {
value: this.initial,
};
},
methods: {
onChange(value) {
this.value = value;
this.$emit('change', value);
}
}
}
</script>
Uygulamaya özel kapsayıcımız artık iş mantığı ile sunum iletişimi arasında köprü olabilir.
// MyAppCard.vue
<template>
<div class="container">
<card-body>
<my-input :initial="serverValue" @change="updateState"></my-input>
<my-input :initial="otherValue" @change="updateState"></my-input>
</card-body>
<card-footer>
<my-button :disabled="!serverValue || !otherValue"
@click="saveState"></my-button>
</card-footer>
</div>
</template>
<script>
import { mapGetters, mapActions } from 'vuex';
import { NS, ACTIONS, GETTERS } from '@/store/modules/api';
import { MyButton, MyInput } from './components';
export default {
components: {
MyInput,
MyButton,
},
computed: mapGetters(NS, [
GETTERS.serverValue,
GETTERS.otherValue,
]),
methods: mapActions(NS, [
ACTIONS.updateState,
ACTIONS.updateState,
])
}
</script>
Vuex mağaza eylemleri arka uç iletişimiyle ilgilendiğinden , buradaki kapsayıcımızın aksiyolar ve arka uç hakkında bilgi sahibi olmasına gerek yoktur.
$emit
v-model
taklit etmek için ile birlikte.sync
. Bence Vuex yoluna