ประเภทการสื่อสาร
เมื่อออกแบบแอปพลิเคชัน Vue (หรือในความเป็นจริงแอปพลิเคชันที่ใช้ส่วนประกอบใด ๆ ) มีประเภทการสื่อสารที่แตกต่างกันขึ้นอยู่กับความกังวลที่เรากำลังเผชิญอยู่และมีช่องทางการสื่อสารของตนเอง
ตรรกะทางธุรกิจ:หมายถึงทุกสิ่งที่เฉพาะเจาะจงสำหรับแอปของคุณและเป้าหมายของแอป
ตรรกะการนำเสนอ:สิ่งใดก็ตามที่ผู้ใช้โต้ตอบหรือเป็นผลมาจากการโต้ตอบจากผู้ใช้
ข้อกังวลทั้งสองนี้เกี่ยวข้องกับการสื่อสารประเภทนี้:
- สถานะแอปพลิเคชัน
- พ่อแม่ลูก
- ผู้ปกครองเด็ก
- พี่น้อง
แต่ละประเภทควรใช้ช่องทางการสื่อสารที่เหมาะสม
ช่องทางการสื่อสาร
ช่องเป็นคำศัพท์หลวม ๆ ที่ฉันจะใช้เพื่ออ้างถึงการใช้งานที่เป็นรูปธรรมเพื่อแลกเปลี่ยนข้อมูลรอบ ๆ แอป Vue
อุปกรณ์ประกอบฉาก: ตรรกะการนำเสนอของผู้ปกครองและเด็ก
ช่องทางการสื่อสารที่ง่ายที่สุดใน Vue สำหรับการสื่อสารระหว่างพ่อแม่และลูกโดยตรง ส่วนใหญ่ควรใช้เพื่อส่งผ่านข้อมูลที่เกี่ยวข้องกับตรรกะการนำเสนอหรือชุดข้อมูลที่ จำกัด ลงตามลำดับชั้น
Refs and method: Presentation anti-pattern
เมื่อไม่สมเหตุสมผลที่จะใช้ไม้ค้ำยันเพื่อให้เด็กจัดการกับเหตุการณ์จากผู้ปกครองการตั้งค่าref
องค์ประกอบลูกและการเรียกใช้วิธีการนั้นก็ใช้ได้
อย่าทำแบบนั้นมันเป็นการต่อต้านรูปแบบ คิดใหม่สถาปัตยกรรมส่วนประกอบและการไหลของข้อมูล หากคุณพบว่าตัวเองต้องการเรียกใช้เมธอดในองค์ประกอบย่อยจากผู้ปกครองอาจถึงเวลาที่ต้องยกระดับสถานะหรือพิจารณาวิธีอื่น ๆ ที่อธิบายไว้ที่นี่หรือในคำตอบอื่น ๆ
เหตุการณ์: ตรรกะการนำเสนอของเด็กและผู้ปกครอง
$emit
และ$on
. ช่องทางการสื่อสารที่ง่ายที่สุดสำหรับการสื่อสารกับเด็กและผู้ปกครองโดยตรง อีกครั้งควรใช้สำหรับตรรกะการนำเสนอ
รถบัสเหตุการณ์
คำตอบส่วนใหญ่ให้ทางเลือกที่ดีสำหรับบัสเหตุการณ์ซึ่งเป็นหนึ่งในช่องทางการสื่อสารที่มีให้สำหรับส่วนประกอบที่อยู่ห่างไกลหรืออะไรก็ได้
สิ่งนี้จะมีประโยชน์เมื่อส่งอุปกรณ์ประกอบฉากไปทั่วสถานที่ตั้งแต่ระยะไกลขึ้นไปจนถึงส่วนประกอบลูกที่ซ้อนกันอย่างลึกซึ้งโดยแทบไม่ต้องใช้ส่วนประกอบอื่นใดเลย ใช้เท่าที่จำเป็นสำหรับข้อมูลที่เลือกอย่างระมัดระวัง
ข้อควรระวัง:การสร้างส่วนประกอบในภายหลังที่ผูกมัดตัวเองกับบัสเหตุการณ์จะถูกผูกไว้มากกว่าหนึ่งครั้งซึ่งจะทำให้ตัวจัดการหลายตัวทริกเกอร์และเกิดการรั่วไหล โดยส่วนตัวแล้วฉันไม่เคยรู้สึกว่าจำเป็นต้องมีรถบัสเหตุการณ์ในแอปหน้าเดียวทั้งหมดที่ฉันเคยออกแบบไว้ในอดีต
ต่อไปนี้แสดงให้เห็นว่าความผิดพลาดง่ายๆนำไปสู่การรั่วไหลโดยที่Item
ส่วนประกอบยังคงทริกเกอร์แม้ว่าจะถูกลบออกจาก DOM ก็ตาม
// 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
ตะขอเกี่ยวกับวงจรชีวิต
ร้านค้าส่วนกลาง (ตรรกะทางธุรกิจ)
Vuexเป็นวิธีที่จะไปกับ Vue สำหรับการจัดการของรัฐ มีมากกว่าแค่งานอีเวนต์และพร้อมสำหรับการใช้งานเต็มรูปแบบ
และตอนนี้คุณถามว่า :
[S] ฉันควรสร้างร้านค้าของ vuex สำหรับการสื่อสารย่อย ๆ หรือไม่?
มันส่องแสงจริงๆเมื่อ:
- จัดการกับตรรกะทางธุรกิจของคุณ
- การสื่อสารกับแบ็กเอนด์ (หรือชั้นการคงอยู่ของข้อมูลเช่นที่เก็บข้อมูลในเครื่อง)
ดังนั้นคอมโพเนนต์ของคุณจึงสามารถมุ่งเน้นไปที่สิ่งที่ควรจะเป็นได้อย่างแท้จริงการจัดการอินเทอร์เฟซผู้ใช้
ไม่ได้หมายความว่าคุณไม่สามารถใช้มันสำหรับตรรกะคอมโพเนนต์ แต่ฉันจะกำหนดขอบเขตตรรกะนั้นให้กับโมดูล Vuex ที่มีการเนมสเปซด้วยสถานะ UI ส่วนกลางที่จำเป็นเท่านั้น
เพื่อหลีกเลี่ยงการจัดการกับทุกสิ่งที่ยุ่งเหยิงในระดับโลกควรแยกร้านค้าออกเป็นโมดูลหลาย ๆ เนมสเปซ
ประเภทส่วนประกอบ
ในการจัดเตรียมการสื่อสารเหล่านี้ทั้งหมดและเพื่อความสะดวกในการใช้งานซ้ำเราควรคิดว่าส่วนประกอบเป็นสองประเภทที่แตกต่างกัน
- คอนเทนเนอร์เฉพาะของแอป
- ส่วนประกอบทั่วไป
อีกครั้งไม่ได้หมายความว่าควรใช้ส่วนประกอบทั่วไปซ้ำหรือไม่สามารถใช้คอนเทนเนอร์เฉพาะของแอปซ้ำได้ แต่มีความรับผิดชอบที่แตกต่างกัน
คอนเทนเนอร์เฉพาะของแอป
สิ่งเหล่านี้เป็นเพียงส่วนประกอบ Vue ง่ายๆที่ห่อส่วนประกอบ Vue อื่น ๆ (คอนเทนเนอร์ทั่วไปหรือคอนเทนเนอร์เฉพาะแอปอื่น ๆ ) นี่คือจุดที่การสื่อสารของร้านค้า Vuex ควรเกิดขึ้นและคอนเทนเนอร์นี้ควรสื่อสารผ่านวิธีการอื่น ๆ ที่ง่ายกว่าเช่นอุปกรณ์ประกอบฉากและผู้ฟังเหตุการณ์
คอนเทนเนอร์เหล่านี้อาจไม่มีองค์ประกอบ DOM ดั้งเดิมเลยและปล่อยให้ส่วนประกอบทั่วไปจัดการกับเทมเพลตและการโต้ตอบกับผู้ใช้
ขอบเขตevents
หรือstores
การมองเห็นอย่างใดสำหรับส่วนประกอบพี่น้อง
นี่คือจุดที่เกิดการกำหนดขอบเขต ส่วนประกอบส่วนใหญ่ไม่ทราบเกี่ยวกับร้านค้าและส่วนประกอบนี้ (ส่วนใหญ่) ควรใช้โมดูลการจัดเก็บเนมสเปซเดียวที่มีชุด จำกัดgetters
และactions
ใช้กับตัวช่วยการผูก Vuex ที่ให้มา
ส่วนประกอบทั่วไป
สิ่งเหล่านี้ควรได้รับข้อมูลจากอุปกรณ์ประกอบฉากทำการเปลี่ยนแปลงข้อมูลในเครื่องของตนเองและปล่อยเหตุการณ์ง่ายๆ ส่วนใหญ่แล้วพวกเขาไม่ควรรู้ว่ามีร้านค้า Vuex อยู่เลย
อาจเรียกได้ว่าเป็นคอนเทนเนอร์เนื่องจากความรับผิดชอบ แต่เพียงผู้เดียวคือการส่งไปยังส่วนประกอบ UI อื่น ๆ
การสื่อสารแบบพี่น้อง
ดังนั้นหลังจากนี้เราควรสื่อสารระหว่างองค์ประกอบพี่น้องสองคนอย่างไร?
ง่ายกว่าที่จะเข้าใจด้วยตัวอย่างเช่นสมมติว่าเรามีช่องป้อนข้อมูลและควรแชร์ข้อมูลในแอป (พี่น้องที่อยู่คนละที่ในต้นไม้) และอยู่กับแบ็กเอนด์
เริ่มต้นด้วยสถานการณ์ที่เลวร้ายที่สุดส่วนประกอบของเราจะผสมผสานการนำเสนอและตรรกะทางธุรกิจ
// 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>
เพื่อแยกข้อกังวลทั้งสองนี้ออกเราควรรวมองค์ประกอบของเราไว้ในคอนเทนเนอร์เฉพาะของแอปและเก็บตรรกะการนำเสนอไว้ในองค์ประกอบการป้อนข้อมูลทั่วไปของเรา
องค์ประกอบการป้อนข้อมูลของเราสามารถใช้ซ้ำได้แล้วและไม่ทราบเกี่ยวกับแบ็กเอนด์หรือพี่น้อง
// 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>
คอนเทนเนอร์เฉพาะแอปของเราสามารถเป็นสะพานเชื่อมระหว่างตรรกะทางธุรกิจและการสื่อสารในการนำเสนอได้แล้ว
// 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 จัดการกับการสื่อสารแบ็กเอนด์คอนเทนเนอร์ของเราที่นี่จึงไม่จำเป็นต้องรู้เกี่ยวกับ axios และแบ็กเอนด์
$emit
รวมกับที่จะเลียนแบบv-model
.sync
ฉันคิดว่าคุณควรไปทาง Vuex