มีอะไรใหม่ใน Vue 3?

เผยแพร่แล้ว: 2022-03-10
สรุปอย่างย่อ ↬ Vue 3 มาพร้อมกับฟีเจอร์ใหม่ที่น่าสนใจมากมายและการเปลี่ยนแปลงบางอย่างที่มีอยู่ซึ่งมุ่งเป้าไปที่การทำให้การพัฒนาด้วยกรอบงานง่ายขึ้นและบำรุงรักษาได้มาก ในบทความนี้ เราจะมาดูคุณสมบัติใหม่เหล่านี้และวิธีเริ่มต้นใช้งาน นอกจากนี้ เรากำลังดูการเปลี่ยนแปลงบางอย่างที่เกิดขึ้นกับคุณลักษณะที่มีอยู่

ด้วยการเปิดตัวของ Vue 3 นักพัฒนาจะต้องทำการอัปเกรดจาก Vue 2 เนื่องจากมาพร้อมกับฟีเจอร์ใหม่จำนวนหนึ่งซึ่งมีประโยชน์มากในการสร้างส่วนประกอบที่อ่านง่ายและบำรุงรักษาได้ และปรับปรุงวิธีจัดโครงสร้างแอปพลิเคชันของเราใน Vue เราจะมาดูคุณสมบัติบางอย่างเหล่านี้ในบทความนี้

ในตอนท้ายของบทช่วยสอนนี้ ผู้อ่านจะ;

  1. รู้จัก provide / inject และวิธีใช้งาน
  2. มีความเข้าใจพื้นฐานเกี่ยวกับ Teleport และวิธีใช้งาน
  3. รู้เกี่ยวกับ Fragment และวิธีใช้งาน
  4. ทราบเกี่ยวกับการเปลี่ยนแปลงที่เกิดขึ้นกับ Global Vue API
  5. ทราบเกี่ยวกับการเปลี่ยนแปลงที่เกิดขึ้นกับ API เหตุการณ์

บทความนี้มุ่งเป้าไปที่ผู้ที่มีความเข้าใจอย่างถูกต้องเกี่ยวกับ Vue 2.x คุณสามารถค้นหาโค้ดทั้งหมดที่ใช้ในตัวอย่างนี้ใน GitHub

provide / inject

ใน Vue 2.x เรามี props ที่ทำให้ง่ายต่อการส่งข้อมูล (สตริง อาร์เรย์ อ็อบเจ็กต์ ฯลฯ) จากองค์ประกอบหลักไปยังองค์ประกอบย่อยโดยตรง แต่ในระหว่างการพัฒนา เรามักพบกรณีที่เราต้องส่งข้อมูลจากองค์ประกอบหลักไปยังองค์ประกอบที่ซ้อนกันอย่างลึกซึ่งยากต่อการทำกับ props ส่งผลให้มีการใช้ Vuex Store, Event Hub และบางครั้งส่งข้อมูลผ่านส่วนประกอบที่ซ้อนกันอย่างลึกล้ำ มาดูแอพง่าย ๆ กัน

สิ่งสำคัญคือต้องทราบว่า Vue 2.2.0 มาพร้อมกับ provide / inject ซึ่งไม่แนะนำให้ใช้ในรหัสแอปพลิเคชันทั่วไป

 # parentComponent.vue <template> <div class="home"> <img alt="Vue logo" src="../assets/logo.png" /> <HelloWorld msg="Vue 3 is liveeeee!" :color="color" /> <select name="color" v-model="color"> <option value="" disabled selected> Select a color</option> <option :value="color" v-for="(color, index) in colors" :key="index">{{ color }}</option></select > </div> </template> <script> import HelloWorld from "@/components/HelloWorld.vue"; export default { name: "Home", components: { HelloWorld, }, data() { return { color: "", colors: ["red", "blue", "green"], }; }, }; </script>
 # childComponent.vue <template> <div class="hello"> <h1>{{ msg }}</h1> <color-selector :color="color"></color-selector> </div> </template> <script> import colorSelector from "@/components/colorComponent.vue"; export default { name: "HelloWorld", components: { colorSelector, }, props: { msg: String, color: String, }, }; </script> <!-- Add "scoped" attribute to limit CSS to this component only --> <style scoped> h3 { margin: 40px 0 0; } ul { list-style-type: none; padding: 0; } li { display: inline-block; margin: 0 10px; } a { color: #42b983; } </style>
 # colorComponent.vue <template> <p :class="[color]">This is an example of deeply nested props!</p> </template> <script> export default { props: { color: String, }, }; </script> <style> .blue { color: blue; } .red { color: red; } .green { color: green; } </style>

ที่นี่ เรามีหน้า Landing Page ที่มีรายการสีแบบดรอปดาวน์ และเราจะส่ง color ที่เลือกไปยัง childComponent.vue เป็นอุปกรณ์ประกอบฉาก องค์ประกอบย่อยนี้ยังมี msg prop ที่ยอมรับข้อความที่จะแสดงในส่วนเทมเพลต สุดท้าย คอมโพเนนต์นี้มีคอมโพเนนต์ย่อย ( colorComponent.vue ) ที่ยอมรับอุปกรณ์ป้องกัน color จากคอมโพเนนต์หลักซึ่งใช้ในการกำหนดคลาสสำหรับข้อความในคอมโพเนนต์นี้ นี่คือตัวอย่างการส่งข้อมูลผ่านส่วนประกอบทั้งหมด

แต่ด้วย Vue 3 เราสามารถทำได้ในระยะสั้นและสะอาดยิ่งขึ้นโดยใช้คู่ Provide และ inject ใหม่ ตามชื่อที่สื่อถึง เราใช้ provide เป็นฟังก์ชันหรืออ็อบเจ็กต์เพื่อให้ข้อมูลพร้อมใช้งานจากองค์ประกอบหลักไปยังองค์ประกอบที่ซ้อนกันไม่ว่าองค์ประกอบดังกล่าวจะซ้อนกันอยู่ลึกเพียงใด เราใช้รูปแบบอ็อบเจ็กต์เมื่อส่งค่าที่ฮาร์ดโค้ดเพื่อ provide ลักษณะเช่นนี้

 # parentComponent.vue <template> <div class="home"> <img alt="Vue logo" src="../assets/logo.png" /> <HelloWorld msg="Vue 3 is liveeeee!" :color="color" /> <select name="color" v-model="color"> <option value="" disabled selected> Select a color</option> <option :value="color" v-for="(color, index) in colors" :key="index">{{ color }}</option></select > </div> </template> <script> import HelloWorld from "@/components/HelloWorld.vue"; export default { name: "Home", components: { HelloWorld, }, data() { return { colors: ["red", "blue", "green"], }; }, provide: { color: 'blue' } }; </script>

แต่สำหรับกรณีที่คุณต้องการส่งคุณสมบัติอินสแตนซ์ส่วนประกอบเพื่อ provide เราใช้โหมดฟังก์ชันเพื่อให้เป็นไปได้

 # parentComponent.vue <template> <div class="home"> <img alt="Vue logo" src="../assets/logo.png" /> <HelloWorld msg="Vue 3 is liveeeee!" /> <select name="color" v-model="selectedColor"> <option value="" disabled selected> Select a color</option> <option :value="color" v-for="(color, index) in colors" :key="index">{{ color }}</option></select > </div> </template> <script> import HelloWorld from "@/components/HelloWorld.vue"; export default { name: "Home", components: { HelloWorld, }, data() { return { selectedColor: "blue", colors: ["red", "blue", "green"], }; }, provide() { return { color: this.selectedColor, }; }, }; </script>

เนื่องจากเราไม่ต้องการอุปกรณ์ประกอบฉาก color ทั้งใน childComponent.vue และ colorComponent.vue เราจึงจะกำจัดมัน สิ่งที่ดีเกี่ยวกับการใช้ provide คือองค์ประกอบหลักไม่จำเป็นต้องรู้ว่าองค์ประกอบใดต้องการคุณสมบัติที่มีให้

เพื่อใช้ประโยชน์จากสิ่งนี้ในส่วนประกอบที่ต้องการในกรณีนี้ colorComponent.vue เราทำเช่นนี้

 # colorComponent.vue <template> <p :class="[color]">This is an example of deeply nested props!</p> </template> <script> export default { inject: ["color"], }; </script> <style> .blue { color: blue; } .red { color: red; } .green { color: green; } </style>

ที่นี่เราใช้ inject ซึ่งรับอาร์เรย์ของตัวแปรที่จำเป็นที่ส่วนประกอบต้องการ ในกรณีนี้ เราต้องการแค่คุณสมบัติ color ดังนั้นเราจึงส่งผ่านมันไปเท่านั้น หลังจากนั้น เราก็สามารถใช้ color แบบเดียวกับที่ใช้กับอุปกรณ์ประกอบฉากได้

เราอาจสังเกตเห็นว่าหากเราพยายามเลือกสีใหม่โดยใช้เมนูแบบเลื่อนลง สีจะไม่อัปเดตใน colorComponent.vue และนี่เป็นเพราะโดยค่าเริ่มต้น คุณสมบัติที่ provide ไว้จะไม่ตอบสนอง ในการแก้ไขปัญหานั้น เราใช้วิธีการ computed

 # parentComponent.vue <template> <div class="home"> <img alt="Vue logo" src="../assets/logo.png" /> <HelloWorld msg="Vue 3 is liveeeee!" /> <select name="color" v-model="selectedColor"> <option value="" disabled selected> Select a color</option> <option :value="color" v-for="(color, index) in colors" :key="index">{{ color }}</option></select > </div> </template> <script> import HelloWorld from "@/components/HelloWorld.vue"; import { computed } from "vue"; export default { name: "Home", components: { HelloWorld, }, data() { return { selectedColor: "", todos: ["Feed a cat", "Buy tickets"], colors: ["red", "blue", "green"], }; }, provide() { return { color: computed(() => this.selectedColor), }; }, }; </script>

ที่นี่ เรานำเข้าจากการ computed และส่งผ่านสีที่เรา selectedColor เพื่อให้สามารถโต้ตอบและอัปเดตได้เมื่อผู้ใช้เลือกสีอื่น เมื่อคุณส่งตัวแปรไปยังวิธีการคำนวณ จะส่งกลับวัตถุที่มี value คุณสมบัตินี้เก็บ ค่า ของตัวแปรของคุณ ดังนั้นสำหรับตัวอย่างนี้ เราจะต้องอัปเดต colorComponent.vue ให้มีลักษณะดังนี้

 # colorComponent.vue <template> <p :class="[color.value]">This is an example of deeply nested props!</p> </template> <script> export default { inject: ["color"], }; </script> <style> .blue { color: blue; } .red { color: red; } .green { color: green; } </style>

ที่นี่ เราเปลี่ยน color เป็น color.value เพื่อแสดงการเปลี่ยนแปลงหลังจากทำปฏิกิริยา color โดยใช้วิธีการ computed ณ จุดนี้ class ของข้อความในส่วนประกอบนี้จะเปลี่ยนไปทุกครั้งที่ selectedColor เปลี่ยนแปลงในองค์ประกอบหลัก

เพิ่มเติมหลังกระโดด! อ่านต่อด้านล่าง↓

เทเลพอร์ต

มีบางกรณีที่เราสร้างส่วนประกอบและวางไว้ในส่วนหนึ่งของแอปพลิเคชันของเราเนื่องจากตรรกะที่แอปใช้ แต่มีจุดมุ่งหมายเพื่อแสดงในส่วนอื่นของแอปพลิเคชันของเรา ตัวอย่างทั่วไปของสิ่งนี้อาจเป็นโมดอลหรือป๊อปอัปที่มีขึ้นเพื่อแสดงและครอบคลุมทั้งหน้าจอ แม้ว่าเราจะสามารถสร้างวิธีแก้ปัญหาสำหรับสิ่งนี้ได้โดยใช้คุณสมบัติ position ของ CSS ในองค์ประกอบดังกล่าว แต่ด้วย Vue 3 เราสามารถทำได้โดยใช้ Teleport

เทเลพอร์ตช่วยให้เราสามารถนำส่วนประกอบออกจากตำแหน่งเดิมในเอกสาร จากค่าเริ่มต้น #app คอนเทนเนอร์ Vue แอปจะถูกห่อและย้ายไปยังองค์ประกอบที่มีอยู่บนหน้าเว็บที่มีการใช้งาน ตัวอย่างที่ดีคือการใช้ Teleport เพื่อย้ายองค์ประกอบส่วนหัวจากภายใน #app div ไปยัง header สิ่งสำคัญที่ควรทราบคือคุณสามารถเทเลพอร์ตไปยังองค์ประกอบที่มีอยู่ภายนอก Vue DOM เท่านั้น

ข้อความแสดงข้อผิดพลาดในคอนโซลเมื่อคุณเทเลพอร์ตไปยังองค์ประกอบที่ไม่ถูกต้อง
ข้อความแสดงข้อผิดพลาด Teleport ในคอนโซล: ข้อความแสดงข้อผิดพลาดเป้าหมาย Teleport ไม่ถูกต้องในเทอร์มินัล (ตัวอย่างขนาดใหญ่)

คอมโพเนนต์ Teleport ยอมรับอุปกรณ์ประกอบฉากสองชิ้นที่กำหนดพฤติกรรมของส่วนประกอบนี้และเป็นไปตามนั้น

  1. to
    พร็อพนี้ยอมรับทั้งชื่อคลาส, id, องค์ประกอบหรือแอตทริบิวต์ data-* นอกจากนี้เรายังสามารถทำให้ค่านี้เป็นไดนามิกโดยส่ง :to prop ตรงข้าม to และเปลี่ยนองค์ประกอบ Teleport แบบไดนามิก
  2. :disabled
    พร็อพนี้ยอมรับ Boolean และสามารถใช้เพื่อสลับคุณสมบัติเทเลพอร์ตบนองค์ประกอบหรือส่วนประกอบ สิ่งนี้มีประโยชน์สำหรับการเปลี่ยนตำแหน่งขององค์ประกอบแบบไดนามิก

ตัวอย่างที่ดีของการใช้ Teleport มีลักษณะดังนี้

 # index.html** <!DOCTYPE html> <html lang="en"> <head> <meta charset="utf-8" /> <meta http-equiv="X-UA-Compatible" content="IE=edge" /> <meta name="viewport" content="width=device-width,initial-scale=1.0" /> <link rel="icon" href="<%= BASE_URL %>favicon.ico" /> <title> <%= htmlWebpackPlugin.options.title %> </title> </head> <!-- add container to teleport to --> <header class="header"></header> <body> <noscript> <strong >We're sorry but <%= htmlWebpackPlugin.options.title %> doesn't work properly without JavaScript enabled. Please enable it to continue.</strong > </noscript> <div></div> <!-- built files will be auto injected --> </body> </html>

ในไฟล์ index.html เริ่มต้นในแอพ Vue ของคุณ เราเพิ่มองค์ประกอบ header เพราะเราต้องการเทเลพอร์ตองค์ประกอบส่วนหัวของเราไปยังจุดนั้นในแอปของเรา เรายังได้เพิ่มคลาสให้กับองค์ประกอบนี้สำหรับการจัดสไตล์และเพื่อการอ้างอิงที่ง่ายในองค์ประกอบ Teleport ของเรา

 # Header.vue** <template> <teleport to="header"> <h1 class="logo">Vue 3 </h1> <nav> <router-link to="/">Home</router-link> </nav> </teleport> </template> <script> export default { name: "app-header", }; </script> <style> .header { display: flex; align-items: center; justify-content: center; } .logo { margin-right: 20px; } </style>

ที่นี่ เราสร้างองค์ประกอบส่วนหัวและเพิ่มโลโก้พร้อมลิงก์ไปยังหน้าแรกในแอปของเรา เรายังเพิ่มองค์ประกอบ Teleport และ to prop ค่าของ header เพราะเราต้องการให้ส่วนประกอบนี้แสดงผลภายในองค์ประกอบนี้ สุดท้าย เรานำเข้าส่วนประกอบนี้ไปยังแอปของเรา

 # App.vue <template> <router-view /> <app-header></app-header> </template> <script> import appHeader from "@/components/Header.vue"; export default { components: { appHeader, }, }; </script>

ในไฟล์นี้ เรานำเข้าองค์ประกอบส่วนหัวและวางไว้ในเทมเพลตเพื่อให้มองเห็นได้ในแอปของเรา

ตอนนี้ หากเราตรวจสอบองค์ประกอบของแอป เราจะสังเกตเห็นว่าองค์ประกอบส่วนหัวอยู่ภายในองค์ประกอบ header

องค์ประกอบส่วนหัวใน DevTools
องค์ประกอบส่วนหัวใน DevTools (ตัวอย่างขนาดใหญ่)

ชิ้นส่วน

ด้วย Vue 2.x เป็นไปไม่ได้ที่จะมีองค์ประกอบรูทหลายรายการใน template ของไฟล์ของคุณ และในการแก้ปัญหาชั่วคราว นักพัฒนาจึงเริ่มห่อองค์ประกอบทั้งหมดในองค์ประกอบหลัก แม้ว่าจะดูไม่เป็นปัญหาร้ายแรง แต่ก็มีบางกรณีที่นักพัฒนาต้องการแสดงส่วนประกอบโดยไม่มีคอนเทนเนอร์ล้อมรอบองค์ประกอบดังกล่าว แต่ต้องดำเนินการด้วย

ด้วย Vue 3 ได้มีการแนะนำคุณลักษณะใหม่ที่เรียกว่า Fragments และคุณลักษณะนี้ช่วยให้นักพัฒนามีองค์ประกอบหลายอย่างในไฟล์เทมเพลตรากของตน ดังนั้นด้วย Vue 2.x นี่คือลักษณะขององค์ประกอบคอนเทนเนอร์ฟิลด์อินพุต

 # inputComponent.vue <template> <div> <label :for="label">label</label> <input :type="type" : :name="label" /> </div> </template> <script> export default { name: "inputField", props: { label: { type: String, required: true, }, type: { type: String, required: true, }, }, }; </script> <style></style>

ในที่นี้ เรามีองค์ประกอบองค์ประกอบแบบฟอร์มอย่างง่ายที่ยอมรับอุปกรณ์ประกอบฉากสองรายการ label และ type และส่วนเทมเพลตขององค์ประกอบนี้รวมอยู่ใน div ไม่จำเป็นต้องเป็นปัญหา แต่ถ้าคุณต้องการให้ป้ายกำกับและช่องป้อนข้อมูลอยู่ภายในองค์ประกอบ form ของคุณโดยตรง ด้วย Vue 3 นักพัฒนาสามารถเขียนองค์ประกอบนี้ใหม่ได้อย่างง่ายดายเพื่อให้มีลักษณะเช่นนี้

 # inputComponent.vue <template class="testingss"> <label :for="label">{{ label }}</label> <input :type="type" : :name="label" /> </template>

ด้วยโหนดรูทเดียว แอตทริบิวต์ จะถูกนำมาประกอบกับโหนดรูทเสมอ และเรียกอีกอย่างว่า แอตทริบิวต์ที่ไม่ใช่อุปกรณ์ ประกอบ เป็นเหตุการณ์หรือแอตทริบิวต์ที่ส่งผ่านไปยังส่วนประกอบที่ไม่มีคุณสมบัติที่เกี่ยวข้องที่กำหนดไว้ใน props หรือการ emits ตัวอย่างของแอตทริบิวต์ดังกล่าว ได้แก่ class และ id อย่างไรก็ตาม จำเป็นต้องกำหนดอย่างชัดเจนว่าองค์ประกอบใดในคอมโพเนนต์โหนดแบบหลายรูทที่ควรนำมาประกอบ

นี่คือสิ่งที่หมายถึงการใช้ inputComponent.vue จากด้านบน;

  1. เมื่อเพิ่ม class ให้กับองค์ประกอบนี้ในองค์ประกอบหลัก จะต้องระบุว่าองค์ประกอบใดที่ class นี้จะถูกนำมาประกอบเป็นอย่างอื่น แอตทริบิวต์จะไม่มีผล
 <template> <div class="home"> <div> <input-component class="awesome__class" label="name" type="text" ></input-component> </div> </div> </template> <style> .awesome__class { border: 1px solid red; } </style>

เมื่อคุณทำสิ่งนี้โดยไม่ได้กำหนดว่าแอตทริบิวต์ควรมาจากที่ใด คุณจะได้รับคำเตือนนี้ในคอนโซลของคุณ

ข้อความแสดงข้อผิดพลาดในเทอร์มินัลเมื่อไม่มีการกระจายแอตทริบิวต์
ข้อความแสดงข้อผิดพลาดในเทอร์มินัลเมื่อไม่มีการกระจายแอตทริบิวต์ (ตัวอย่างขนาดใหญ่)

และ border ไม่มีผลกับส่วนประกอบ

องค์ประกอบที่ไม่มีการกระจายแอตทริบิวต์
ส่วนประกอบที่ไม่มีการกระจายแอตทริบิวต์ (ตัวอย่างขนาดใหญ่)
  1. ในการแก้ไขปัญหานี้ ให้เพิ่ม v-bind="$attrs" ในองค์ประกอบที่คุณต้องการแจกจ่ายแอตทริบิวต์ดังกล่าว
 <template> <label :for="label" v-bind="$attrs">{{ label }}</label> <input :type="type" : :name="label" /> </template>

ที่นี่ เรากำลังบอก Vue ว่าเราต้องการให้แอตทริบิวต์ถูกแจกจ่ายไปยังองค์ประกอบ label ซึ่งหมายความว่าเราต้องการใช้ awesome__class กับมัน ตอนนี้ หากเราตรวจสอบองค์ประกอบของเราในเบราว์เซอร์ เราจะเห็นว่าขณะนี้มีการเพิ่มคลาสใน label และด้วยเหตุนี้จึงมีเส้นขอบรอบป้ายกำกับ

ส่วนประกอบที่มีการกระจายแอตทริบิวต์
ส่วนประกอบที่มีการกระจายแอตทริบิวต์ (ตัวอย่างขนาดใหญ่)

Global API

ไม่ใช่เรื่องแปลกที่จะเห็น Vue.component หรือ Vue.use ในไฟล์ main.js ของแอปพลิเคชัน Vue เมธอดประเภทนี้รู้จักกันดีคือ Global APIs และมีหลายวิธีใน Vue 2.x ความท้าทายอย่างหนึ่งของวิธีนี้คือทำให้ไม่สามารถแยกฟังก์ชันการทำงานบางอย่างกับอินสแตนซ์หนึ่งของแอปของคุณ (ถ้าคุณมีมากกว่าหนึ่งอินสแตนซ์ในแอปของคุณ) โดยไม่ส่งผลต่อแอปอื่นๆ เนื่องจากทั้งหมดติดตั้งอยู่บน Vue นี่คือสิ่งที่ผมหมายถึง

 Vue.directive('focus', { inserted: el => el.focus() }) Vue.mixin({ /* ... */ }) const app1 = new Vue({ el: '#app-1' }) const app2 = new Vue({ el: '#app-2' })

สำหรับโค้ดด้านบนนี้ เป็นไปไม่ได้ที่จะระบุว่า Vue Directive เชื่อมโยงกับ app1 และ Mixin กับ app2 แทน แต่ทั้งสองมีอยู่ในทั้งสองแอปแทน

Vue 3 มาพร้อมกับ Global API ใหม่ในความพยายามที่จะแก้ไขปัญหาประเภทนี้ด้วยการเปิดตัว createApp วิธีนี้จะคืนค่าอินสแตนซ์ใหม่ของแอป Vue อินสแตนซ์ของแอปเปิดเผยชุดย่อยของ API ส่วนกลางปัจจุบัน ด้วยวิธีนี้ API ทั้งหมด (ส่วนประกอบ มิกซ์อิน คำสั่ง การใช้งาน ฯลฯ) ที่เปลี่ยน Vue จาก Vue 2.x จะถูกย้ายไปยังอินสแตนซ์ของแอปแต่ละรายการ และตอนนี้ แต่ละอินสแตนซ์ของแอป Vue สามารถมีฟังก์ชันการทำงานเฉพาะสำหรับ โดยไม่กระทบต่อแอพอื่นๆ ที่มีอยู่

ตอนนี้โค้ดข้างต้นสามารถเขียนใหม่เป็น;

 const app1 = createApp({}) const app2 = createApp({}) app1.directive('focus', { inserted: el => el.focus() }) app2.mixin({ /* ... */ })

อย่างไรก็ตาม คุณสามารถสร้างฟังก์ชันที่คุณต้องการแชร์กับแอปทั้งหมดของคุณได้ ซึ่งสามารถทำได้โดยใช้ฟังก์ชันจากโรงงาน

เหตุการณ์ API

วิธีหนึ่งที่นักพัฒนามักนำมาใช้เพื่อส่งข้อมูลระหว่างส่วนประกอบที่ไม่มีความสัมพันธ์แบบพาเรนต์ถึงลูกนอกเหนือจากการใช้ Vuex Store คือการใช้ Event Bus สาเหตุหนึ่งที่ทำให้วิธีนี้เป็นเรื่องปกติเพราะความง่ายในการเริ่มต้น

 # eventBus.js const eventBus = new Vue() export default eventBus;

หลังจากนี้ สิ่งต่อไปคือการนำเข้าไฟล์นี้ไปยัง main.js เพื่อให้สามารถใช้งานได้ทั่วโลกในแอพของเรา หรือเพื่อนำเข้าในไฟล์ที่คุณต้องการ

 # main.js import eventBus from 'eventBus' Vue.prototype.$eventBus = eventBus

ตอนนี้คุณสามารถปล่อยเหตุการณ์และฟังเหตุการณ์ที่ปล่อยออกมาเช่นนี้

 this.$eventBus.$on('say-hello', alertMe) this.$eventBus.$emit('pass-message', 'Event Bus says Hi')

มี Vue codebase มากมายที่เต็มไปด้วยโค้ดแบบนี้ อย่างไรก็ตาม ด้วย Vue 3 จะไม่สามารถดำเนินการได้ เนื่องจาก $on , $off และ $once on ถูกลบออกทั้งหมดแล้ว แต่ $emit ยังคงใช้งานได้เนื่องจากจำเป็นสำหรับองค์ประกอบลูกในการส่งเหตุการณ์ไปยังองค์ประกอบหลัก อีกทางเลือกหนึ่งคือการใช้ provide / inject หรือไลบรารีของบุคคลที่สามที่แนะนำ

บทสรุป

ในบทความนี้ เราได้กล่าวถึงวิธีที่คุณสามารถส่งข้อมูลไปรอบๆ จากองค์ประกอบหลักลงไปที่องค์ประกอบย่อยที่ซ้อนกันอย่างล้ำลึกโดยใช้คู่การ provide / inject นอกจากนี้เรายังได้พิจารณาถึงวิธีที่เราสามารถเปลี่ยนตำแหน่งและถ่ายโอนส่วนประกอบจากจุดหนึ่งในแอพของเราไปยังอีกจุดหนึ่ง อีกสิ่งหนึ่งที่เราดูคือคอมโพเนนต์โหนดหลายรูทและจะแน่ใจได้อย่างไรว่าเราแจกจ่ายแอตทริบิวต์เพื่อให้ทำงานได้อย่างถูกต้อง สุดท้าย เรายังครอบคลุมถึงการเปลี่ยนแปลงของ Events API และ Global API

แหล่งข้อมูลเพิ่มเติม

  • “ฟังก์ชั่นโรงงาน JavaScript กับ ES6+” Eric Elliott, Medium
  • “การใช้ Event Bus เพื่อแบ่งปันอุปกรณ์ประกอบฉากระหว่างส่วนประกอบ Vue” Kingsley Silas, CSS-Tricks
  • การใช้เทเลพอร์ตหลายรายการในเป้าหมายเดียวกัน Vue.js Docs
  • แอตทริบิวต์ที่ไม่ใช่อุปกรณ์ประกอบฉาก, Vue.js Docs
  • การทำงานกับปฏิกิริยา Vue.js Docs
  • teleport เลพอร์ต , Vue.js Docs
  • Fragments, Vue.js Docs
  • ไวยากรณ์ 2.x, Vue.js Docs