วิธีส่งข้อมูลระหว่างส่วนประกอบใน Vue.js
เผยแพร่แล้ว: 2022-03-10การแชร์ข้อมูลระหว่างส่วนประกอบเป็นหนึ่งในฟังก์ชันหลักของ VueJS ช่วยให้คุณออกแบบโปรเจ็กต์แบบแยกส่วนได้มากขึ้น ควบคุมขอบเขตข้อมูล และสร้างโฟลว์ข้อมูลอย่างเป็นธรรมชาติทั่วทั้งแอปของคุณ
เว้นแต่ว่าคุณกำลังสร้างแอป Vue ทั้งหมดของคุณในองค์ประกอบเดียว (ซึ่งไม่สมเหตุสมผลเลย) คุณจะพบสถานการณ์ที่คุณต้องการแชร์ข้อมูลระหว่างส่วนประกอบต่างๆ
ในตอนท้ายของบทช่วยสอนนี้ คุณจะรู้สามวิธีในการทำสิ่งนี้ให้สำเร็จ
- การใช้อุปกรณ์ประกอบฉากเพื่อแบ่งปันข้อมูลจากผู้ปกครองไปยังเด็ก
- ปล่อยเหตุการณ์ที่กำหนดเองเพื่อแบ่งปันข้อมูลจากลูกไปยังผู้ปกครอง
- การใช้ Vuex เพื่อสร้างสถานะแชร์ระดับแอป
โอเค - มาเริ่มกันเลย!
สร้างแอปด้วย Nuxt
ด้วย Spotify เพื่อนๆ ของคุณสามารถตรวจสอบสิ่งที่คุณกำลังติดขัดได้ จะเกิดอะไรขึ้นถ้าอินเทอร์เน็ตที่เหลือสามารถสัมผัสกับอัลกอฮอล์ของคุณได้เช่นกัน เรียนรู้วิธีเขียนแอปของคุณเองเพื่อแชร์สิ่งที่คุณกำลังฟังบน Spotify โดยใช้ Vue.js และ Nuxt อ่านบทความที่เกี่ยวข้อง →
1. การใช้อุปกรณ์ประกอบฉากเพื่อแบ่งปันข้อมูลจากผู้ปกครองถึงเด็ก
อุปกรณ์ประกอบฉาก VueJS เป็นวิธีที่ง่ายที่สุดในการแบ่งปันข้อมูลระหว่างส่วนประกอบต่างๆ อุปกรณ์ประกอบฉากคือแอตทริบิวต์ที่กำหนดเองซึ่งเราสามารถมอบให้กับส่วนประกอบได้ จากนั้นในเทมเพลตของเรา เราสามารถให้ค่าแอตทริบิวต์เหล่านั้นและ — BAM — เรากำลังส่งข้อมูลจากพาเรนต์ไปยังองค์ประกอบย่อย!
ตัวอย่างเช่น สมมติว่าเรากำลังดำเนินการในหน้าโปรไฟล์ผู้ใช้และต้องการให้องค์ประกอบย่อยยอมรับชื่อผู้ใช้ เราต้องการสององค์ประกอบ
- องค์ประกอบลูกที่ยอมรับพร็อพ ให้เรียกสิ่งนี้ว่า
AccountInfo.vue
- องค์ประกอบหลักที่ส่งผ่าน prop ให้เรียก
ProfilePage.vue
นี้
ภายใน AccountInfo.vue
เราสามารถประกาศอุปกรณ์ประกอบฉากที่ยอมรับโดยใช้ตัวเลือกอุปกรณ์ประกอบฉาก ดังนั้น ภายในตัวเลือกส่วนประกอบ เรามาทำให้มันมีลักษณะดังนี้
// AccountInfo.vue <template> <div id='account-info'> {{username}} </div> </template> <script> export default { props: ['username'] } </script>
จากนั้น ในการส่งข้อมูลจากพาเรนต์ ( ProfilePage.vue
) เราส่งผ่านเหมือนแอตทริบิวต์ที่กำหนดเอง
// ProfilePage.vue <account-info username='matt' />
ตอนนี้ หากเราโหลดหน้าเว็บ เราจะเห็นว่าองค์ประกอบ AccountInfo
ของเราแสดงค่าที่ส่งผ่านโดยพาเรนต์อย่างถูกต้อง
เมื่อทำงานกับคำสั่ง VueJS อื่นๆ เราสามารถใช้ v-bind เพื่อส่งผ่านอุปกรณ์ประกอบฉากแบบไดนามิก ตัวอย่างเช่น สมมติว่าเราต้องการตั้งค่า username prop ให้เท่ากับตัวแปร เราสามารถทำได้โดยใช้ชวเลขสำหรับคำสั่ง v-bind (หรือเพียง :
สำหรับระยะสั้น) รหัสจะมีลักษณะดังนี้:
<template> <div> <account-info :username="user.username" /> </div> </template> <script> import AccountInfo from "@/components/AccountInfo.vue"; export default { components: { AccountInfo }, data() { return { user: { username: 'matt' } } } } </script>
ซึ่งหมายความว่าเราสามารถเปลี่ยนแปลงข้อมูลของเราและมีอุปกรณ์ประกอบฉากย่อยที่ใช้ค่านั้นจะได้รับการอัปเดตด้วย
เคล็ดลับ: ตรวจสอบอุปกรณ์ประกอบฉากของคุณเสมอ
หากคุณต้องการเขียนโค้ด Vue ให้ชัดเจนขึ้น เทคนิคที่สำคัญคือการตรวจสอบอุปกรณ์ประกอบฉากของคุณ กล่าวโดยย่อ หมายความว่าคุณต้องระบุข้อกำหนดสำหรับพร็อพของคุณ (เช่น ประเภท รูปแบบ และอื่นๆ) หากไม่เป็นไปตามข้อกำหนดข้อใดข้อหนึ่ง (เช่น หากอุปกรณ์ส่งผ่านประเภทที่ไม่ถูกต้อง) Vue จะพิมพ์คำเตือนออกมา
สมมติว่าเราต้องการให้ชื่อผู้ใช้ของเรายอมรับสตริงเท่านั้น เราจะต้องแก้ไขวัตถุ props ของเราให้มีลักษณะดังนี้:
export default { props: { username: String } }
การตรวจสอบอุปกรณ์ประกอบฉากเป็นสิ่งสำคัญเมื่อทำงานในแอป Vue ขนาดใหญ่หรือเมื่อออกแบบปลั๊กอิน ช่วยให้แน่ใจว่าทุกคนเข้าใจตรงกันและใช้อุปกรณ์ประกอบฉากตามที่ตั้งใจไว้
สำหรับรายการการตรวจสอบทั้งหมดที่เราสามารถรวมไว้ในอุปกรณ์ประกอบฉากได้ ฉันขอแนะนำให้ตรวจสอบเอกสารอย่างเป็นทางการสำหรับการตรวจสอบในเชิงลึก
เคล็ดลับ: ปฏิบัติตามอนุสัญญาการตั้งชื่อพร็อพ
ตามคู่มือสไตล์ VueJS วิธีที่ดีที่สุดในการตั้งชื่อพร็อพของคุณคือการใช้ camelCase
เมื่อประกาศในสคริปต์และ kebab-case เมื่ออ้างอิงถึงพวกมันในโค้ดเทมเพลต
เหตุผลเบื้องหลังเรื่องนี้ค่อนข้างง่าย ใน Javascript นั้น camelCase
เป็นรูปแบบการตั้งชื่อมาตรฐานและใน HTML มันคือ kebab-case
ดังนั้น Vue ขอแนะนำให้เรายึดมั่นในบรรทัดฐานของแต่ละภาษา โชคดีที่ Vue สามารถแปลงระหว่างสองสไตล์ได้โดยอัตโนมัติ ดังนั้นจึงไม่มีการตั้งค่าเพิ่มเติมสำหรับนักพัฒนา
// GOOD <account-info :my-username="user.username" /> props: { myUsername: String } // BAD <account-info :myUsername="user.username" /> props: { "my-username": String }
2. การปล่อยเหตุการณ์เพื่อแบ่งปันข้อมูลจากเด็กถึงผู้ปกครอง
ตอนนี้เรามีข้อมูลที่ส่งผ่านลำดับชั้นแล้ว เรามาส่งต่อกันในอีกทางหนึ่ง: จากองค์ประกอบลูกไปยังพาเรนต์ เราไม่สามารถใช้อุปกรณ์ประกอบฉาก แต่เราสามารถใช้เหตุการณ์และผู้ฟังที่กำหนดเองได้
ทุกอินสแตนซ์ของ Vue สามารถเรียกเมธอด .$emit(eventName)
ที่ทริกเกอร์เหตุการณ์ได้ จากนั้น เราสามารถฟังเหตุการณ์นี้ในลักษณะเดียวกับงานอื่นๆ โดยใช้คำสั่ง v-on
การสร้างเหตุการณ์ที่กำหนดเอง
มาสร้างจากตัวอย่างโปรไฟล์ผู้ใช้ของเราโดยเพิ่มปุ่มที่เปลี่ยนชื่อผู้ใช้ ภายในองค์ประกอบลูกของเรา ( AccountInfo.vue
) มาสร้างปุ่มกัน
จากนั้น เมื่อคลิกปุ่มนี้ เราจะปล่อยเหตุการณ์ที่เรียกว่า changeUsername
<template> <div id='account-info'> <button @click='changeUsername()'>Change Username</button> {{username}} </div> </template> <script> export default { props: { username: String }, methods: { changeUsername() { this.$emit('changeUsername') } } } </script>
ภายในพาเรนต์ เราจัดการเหตุการณ์นี้และเปลี่ยนตัวแปร user.username
เช่นเดียวกับที่เราได้พูดคุยกันก่อนหน้านี้ เราสามารถฟังเหตุการณ์โดยใช้คำสั่ง v-on หรือ "@" สั้นๆ
<template> <div> <account-info :username="user.username" @changeUsername="user.username = 'new name'"/> </div> </template>
มาลองดูกัน คุณควรเห็นว่าเมื่อคุณคลิกปุ่ม ชื่อผู้ใช้จะเปลี่ยนเป็น "ชื่อใหม่"
เคล็ดลับ: เหตุการณ์ที่กำหนดเองสามารถยอมรับอาร์กิวเมนต์ได้
กรณีการใช้งานที่พบบ่อยที่สุดสำหรับการส่งผ่านอาร์กิวเมนต์ไปยังเหตุการณ์ของคุณคือเมื่อคุณต้องการให้องค์ประกอบลูกสามารถตั้งค่าเฉพาะสำหรับเสาได้ คุณ ไม่ ต้องการแก้ไขค่าของพร็อพจากส่วนประกอบโดยตรง
อย่างไรก็ตาม โชคดีที่เราสามารถใช้อาร์กิวเมนต์ pass กับเหตุการณ์ที่กำหนดเองของเราเพื่อสร้างค่าการเปลี่ยนแปลงองค์ประกอบหลัก
สมมติว่าเราต้องการแก้ไขเหตุการณ์ changeUsername
เพื่อให้เราสามารถส่งต่อค่าได้
วิธี $emit
ใช้พารามิเตอร์ตัวที่สองที่เป็นทางเลือกสำหรับอาร์กิวเมนต์ สิ่งที่เราทำคือเพิ่มค่าชื่อผู้ใช้ใหม่ของเราหลังชื่อกิจกรรมของเรา
this.$emit('changeUsername', 'mattmaribojoc')
จากนั้นในองค์ประกอบหลักของเรา เราสามารถเข้าถึงค่าเหล่านี้แบบอินไลน์โดยใช้ตัวแปรพิเศษ $event
หรือเราสามารถเขียนวิธีจัดการที่ใช้พารามิเตอร์ได้
<account-info :username="user.username" @changeUsername="user.username = $event"/> OR <account-info :username="user.username" @changeUsername="changeUsername($event)"/> export default { ... methods: { changeUsername (username) { this.user.username = username; } } }
3. การใช้ Vuex เพื่อสร้างสถานะแชร์ระดับแอปพลิเคชัน
โอเค เรารู้วิธีแชร์ข้อมูลระหว่างพ่อแม่/ลูก แล้วองค์ประกอบอื่นๆ ล่ะ เราต้องสร้างระบบลำดับชั้นที่ซับซ้อนอย่างยิ่งถ้าเราต้องการส่งข้อมูลหรือไม่?
โชคดีที่ไม่ ห้องสมุดการจัดการสถานะ Vuex ที่ยอดเยี่ยมทำให้ชีวิตของนักพัฒนาง่ายขึ้นมาหลายปีแล้ว กล่าวโดยย่อ จะสร้างที่เก็บข้อมูลแบบรวมศูนย์ที่ส่วนประกอบทั้งหมดสามารถเข้าถึงได้
ในวิธีที่เราใช้ก่อนหน้านี้ (props / emitting events) แต่ละองค์ประกอบมีสถานะข้อมูลของตัวเองที่เราแชร์ระหว่างส่วนประกอบ อย่างไรก็ตาม Vuex ช่วยให้เราดึงข้อมูลที่ใช้ร่วมกันทั้งหมดไว้ในสถานะเดียวที่แต่ละองค์ประกอบสามารถเข้าถึงได้ง่าย สถานะที่ใช้ร่วมกันนี้เรียกว่าร้านค้า
มาลองดูกัน
เนื่องจาก Vuex นั้นแยกจากโค้ดหลักของ Vue เราจึงต้องติดตั้งและนำเข้าไปยังโครงการของเราก่อน อันดับแรก เราจะต้องเรียกใช้ npm install vuex --save
ภายในโครงการ CLI ของเรา
จากนั้น สร้างโฟลเดอร์ src/store ด้วยไฟล์ index.js ที่มีโค้ดต่อไปนี้
// store/index.js import Vue from "vue"; import Vuex from "vuex"; Vue.use(Vuex); export default new Vuex.Store({ state: {}, getters: {}, mutations: {}, actions: {} });
ในการรวมสิ่งนี้ในอินสแตนซ์รูท Vue ของเรา เราต้องนำเข้าไฟล์ store/index.js และส่งผ่านไปยังตัวสร้าง Vue ของเรา
// main.js import store from "./store"; new Vue({ store, ...
การเข้าถึง Vue Store Inside Components
เนื่องจากเราเพิ่มที่เก็บ Vuex ของเราลงในอินสแตนซ์รูท Vue จึงถูกฉีดเข้าไปในรายการย่อยของรูททั้งหมด หากเราต้องการเข้าถึงร้านค้าจากส่วนประกอบ เราสามารถทำได้ผ่าน this.$store
ตอนนี้ มาเจาะลึกรายละเอียดเฉพาะของแต่ละส่วนสี่ส่วนของร้าน Vuec
1. รัฐ
สถานะ Vuex เป็นอ็อบเจ็กต์ที่มีข้อมูลระดับแอปพลิเคชัน อินสแตนซ์ Vue ทั้งหมดจะสามารถเข้าถึงข้อมูลนี้ได้
สำหรับร้านค้าของเรา ให้สร้างวัตถุผู้ใช้ที่เก็บข้อมูลโปรไฟล์ผู้ใช้เพิ่มเติม
export default new Vuex.Store({ state: { user: { username: 'matt', fullName: 'Matt Maribojoc' } }, getters: {}, mutations: {}, actions: {} });
เราสามารถเข้าถึงข้อมูลนี้ภายในองค์ประกอบอินสแตนซ์ใดๆ เช่นนี้
mounted () { console.log(this.$store.state.user.username); },
2. Getters
เราใช้ Vuex getters เพื่อคืนค่าข้อมูลสถานะที่แก้ไข วิธีที่ดีในการนึกถึงผู้รับคือปฏิบัติต่อพวกเขาเหมือนคุณสมบัติที่คำนวณได้ ตัวอย่างเช่น getters เช่นคุณสมบัติที่คำนวณ แคชผลลัพธ์และประเมินใหม่เฉพาะเมื่อมีการแก้ไขการขึ้นต่อกันเท่านั้น
ต่อจากสโตร์ก่อนหน้านี้ สมมติว่าเราต้องการสร้างวิธีการที่ส่งกลับชื่อจริงของผู้ใช้ตามแอตทริบิวต์ชื่อเต็ม
getters: { firstName: state => { return state.user.fullName.split(' ')[0] } }
คุณสมบัติ Vuex getter พร้อมใช้งานสำหรับส่วนประกอบบนอ็อบเจ็กต์ store.getters
mounted () { console.log(this.$store.getters.firstName); }
เคล็ดลับ: รู้จักอาร์กิวเมนต์ Getter เริ่มต้น
โดยค่าเริ่มต้น Vuex getters ยอมรับสองอาร์กิวเมนต์
- state — สถานะอ็อบเจ็กต์สำหรับแอปพลิเคชันของเรา
- getters — อ็อบเจ็กต์ store.getters หมายความว่าเราสามารถเรียก getters คนอื่นๆ ในร้านของเราได้
getter ทุกคนที่คุณประกาศจะต้องมีอาร์กิวเมนต์สถานะแรก และขึ้นอยู่กับว่าคุณออกแบบโค้ดอย่างไร getters ของคุณสามารถอ้างอิงถึงกันได้โดยใช้อาร์กิวเมนต์ 'getters' ที่สอง
มาสร้างตัวรับนามสกุลที่เพียงแค่ลบค่าชื่อของเราออกจากคุณสมบัติสถานะชื่อเต็มของเรา ตัวอย่างนี้จะต้องใช้ทั้งอ็อบเจ็กต์ state และ getters
lastName (state, getters) { return state.user.fullName.replace(getters.firstName, ''); }
เคล็ดลับ: ส่งผ่านอาร์กิวเมนต์ที่กำหนดเองไปยัง Vuex Getters
คุณลักษณะที่ยอดเยี่ยมอีกประการหนึ่งของ getters คือเราสามารถส่งอาร์กิวเมนต์ที่กำหนดเองได้โดยทำให้ getter ส่งคืนวิธีการ
prefixedName: (state, getters) => (prefix) => { return prefix + getters.lastName; } // in our component console.log(this.$store.getters.prefixedName("Mr."));
3. การกลายพันธุ์
การกลายพันธุ์เป็นวิธี เดียว ที่จะเปลี่ยนค่าของ state object ได้อย่างถูกต้อง รายละเอียดสำคัญที่ควรทราบคือการกลายพันธุ์ ต้องซิงโครนั ส
เช่นเดียวกับ getters การกลายพันธุ์จะยอมรับคุณสมบัติสถานะ Vuex เป็นอาร์กิวเมนต์แรกเสมอ พวกเขายังยอมรับอาร์กิวเมนต์ที่กำหนดเอง ซึ่งเรียกว่า payload เป็นอาร์กิวเมนต์ที่สอง
ตัวอย่างเช่น มาทำการกลายพันธุ์เพื่อเปลี่ยนชื่อของผู้ใช้เป็นค่าเฉพาะ
mutations: { changeName (state, payload) { state.user.fullName = payload } },
จากนั้น เราสามารถเรียกวิธีนี้จากคอมโพเนนต์ของเราโดยใช้เมธอด store.commit
โดยมีเพย์โหลดเป็นอาร์กิวเมนต์ที่สอง
this.$store.commit("changeName", "New Name");
บ่อยครั้งคุณต้องการให้ payload ของคุณเป็นวัตถุ นี่ไม่เพียงหมายความว่าคุณสามารถส่งผ่านอาร์กิวเมนต์หลายตัวไปยังการกลายพันธุ์ได้ แต่ยังทำให้โค้ดของคุณอ่านง่ายขึ้นเนื่องจากชื่อคุณสมบัติในออบเจกต์ของคุณ
changeName (state, payload) { state.user.fullName = payload.newName }
มีสองวิธีในการเรียกการกลายพันธุ์ด้วยเพย์โหลด
- คุณสามารถมีประเภทการกลายพันธุ์เป็นอาร์กิวเมนต์แรกและเพย์โหลดเป็นอาร์กิวเมนต์ที่สองได้
- คุณสามารถประกาศผ่านอ็อบเจ็กต์เดียว โดยมีคุณสมบัติหนึ่งสำหรับประเภทและอีกรายการสำหรับเพย์โหลด
this.$store.commit("changeName", { newName: "New Name 1", }); // or this.$store.commit({ type: "changeName", newName: "New Name 2" });
ไม่มีความแตกต่างระหว่างวิธีการทำงานทั้งสองอย่างแท้จริง ดังนั้นจึงขึ้นอยู่กับความชอบส่วนบุคคลโดยสิ้นเชิง จำไว้ว่าคุณควรมีความสม่ำเสมอตลอดทั้งโปรเจ็กต์ของคุณ ไม่ว่าคุณจะเลือกอันไหน ให้ยึดติดกับมัน!
4. การกระทำ
ใน Vuex การกระทำค่อนข้างคล้ายกับการกลายพันธุ์เพราะเราใช้พวกมันเพื่อเปลี่ยนสถานะ อย่างไรก็ตาม การกระทำไม่ได้เปลี่ยนค่าเอง การกระทำทำให้เกิดการกลายพันธุ์แทน
นอกจากนี้ แม้ว่าการกลายพันธุ์ของ Vuex จะต้องเป็นแบบซิงโครนัส การดำเนินการจะไม่ทำ การใช้การกระทำ เราสามารถเรียกการกลายพันธุ์หลังจากการเรียก API เป็นต้น
ในขณะที่ตัวจัดการ Vuex ส่วนใหญ่เราเห็นสถานะที่ยอมรับเป็นพารามิเตอร์หลัก การดำเนินการยอมรับวัตถุบริบท ออบเจ็กต์บริบทนี้ช่วยให้เราเข้าถึงคุณสมบัติในร้านค้า Vuex ของเราได้ (เช่น สถานะ การคอมมิต ผู้ได้รับ)
ต่อไปนี้คือตัวอย่างการดำเนินการของ Vuex ที่รอสองวินาทีแล้วส่งการกลายพันธุ์ของ changeName
actions: { changeName (context, payload) { setTimeout(() => { context.commit("changeName", payload); }, 2000); } }
ภายในส่วนประกอบของเรา เราใช้เมธอด store.dispatch เพื่อเรียกใช้ฟังก์ชันของเรา เราส่งผ่านอาร์กิวเมนต์เหมือนกับที่เราทำกับการกลายพันธุ์ เราประกาศประเภทและเราส่งอาร์กิวเมนต์ที่กำหนดเองในอาร์กิวเมนต์ที่สอง
this.$store.dispatch("changeName", { newName: "New Name from Action" });
ห่อ
ตอนนี้ คุณควรทราบสามวิธีในการแบ่งปันข้อมูลระหว่างส่วนประกอบต่างๆ ใน VueJS: อุปกรณ์ประกอบฉาก เหตุการณ์ที่กำหนดเอง และร้านค้า Vuex
ฉันหวังว่าบทช่วยสอนนี้จะช่วยให้คุณเข้าใจมากขึ้นเกี่ยวกับวิธีการต่างๆ ของ Vue และแนวทางปฏิบัติที่ดีที่สุด แจ้งให้เราทราบว่าคุณได้นำไปใช้ในโครงการของคุณอย่างไร!
อ่านเพิ่มเติม
หากคุณสนใจที่จะเจาะลึกลงไปในด้านเทคนิค/ความสามารถของแต่ละเทคนิค ต่อไปนี้คือจุดเริ่มต้นที่ดี
- เว็บไซต์คู่มืออย่างเป็นทางการของ Vuex
- VueJS Docs สำหรับอุปกรณ์ประกอบฉากและเหตุการณ์ที่กำหนดเอง
- “WTF คือ Vuex? คู่มือสำหรับผู้เริ่มต้นในการจัดเก็บข้อมูลแอปพลิเคชันของ Vue” Anthony Gore ผู้พัฒนา Vue.js