นอกเหนือจาก การปรับปรุงประสิทธิภาพที่น่าชื่นชม Vue 3 ที่เพิ่งเปิดตัวเมื่อเร็ว ๆ นี้ยังมีคุณสมบัติใหม่ ๆ อีกมากมาย บทนำที่สำคัญที่สุดคือไฟล์ Composition API . ในส่วนแรกของบทความนี้เราสรุปแรงจูงใจมาตรฐานสำหรับ API ใหม่: การจัดระเบียบรหัสที่ดีขึ้นและการใช้ซ้ำ ในส่วนที่สองเราจะเน้นไปที่แง่มุมที่ไม่ค่อยมีการพูดถึงในการใช้ API ใหม่เช่นการใช้คุณลักษณะที่อิงตามปฏิกิริยาซึ่งไม่สามารถแสดงออกได้ในระบบปฏิกิริยาของ Vue 2
เราจะอ้างถึงสิ่งนี้ว่า ปฏิกิริยาตามความต้องการ . หลังจากเปิดตัวคุณลักษณะใหม่ที่เกี่ยวข้องแล้วเราจะสร้างแอปพลิเคชันสเปรดชีตอย่างง่ายเพื่อแสดงให้เห็นถึงการแสดงออกใหม่ของระบบปฏิกิริยาของ Vue ในตอนท้ายเราจะพูดถึงสิ่งที่ในโลกแห่งความจริงใช้การปรับปรุงปฏิกิริยาตามความต้องการที่อาจมี
ดู 3 คือ การเขียนซ้ำครั้งใหญ่ของ Vue 2 แนะนำการปรับปรุงมากมายในขณะที่ยังคงความเข้ากันได้แบบย้อนหลังกับ API เก่า เกือบครบถ้วน .
หนึ่งในคุณสมบัติใหม่ที่สำคัญที่สุดใน Vue 3 คือ Composition API . การแนะนำของมันจุดประกายมาก การโต้เถียง เมื่อมีการพูดคุยต่อสาธารณะเป็นครั้งแรก ในกรณีที่คุณยังไม่คุ้นเคยกับ API ใหม่ก่อนอื่นเราจะอธิบายถึงแรงจูงใจที่อยู่เบื้องหลัง
หน่วยของรหัสตามปกติคือออบเจ็กต์ JavaScript ที่มีคีย์เป็นตัวแทนของส่วนประกอบที่เป็นไปได้หลายประเภท ดังนั้นวัตถุอาจมีส่วนหนึ่งสำหรับข้อมูลปฏิกิริยา (data
) อีกส่วนหนึ่งสำหรับคุณสมบัติที่คำนวณ (computed
) อีกหนึ่งส่วนสำหรับเมธอดคอมโพเนนต์ (methods
) เป็นต้น
ภายใต้กระบวนทัศน์นี้คอมโพเนนต์สามารถมีฟังก์ชันที่ไม่เกี่ยวข้องกันหรือเกี่ยวข้องกันได้หลายอย่างซึ่งการทำงานภายในจะกระจายไปตามส่วนขององค์ประกอบดังกล่าว ตัวอย่างเช่นเราอาจมีองค์ประกอบสำหรับการอัปโหลดไฟล์ที่ใช้ฟังก์ชันการทำงานสองอย่างที่แยกจากกัน: การจัดการไฟล์และระบบที่ควบคุมภาพเคลื่อนไหวสถานะการอัปโหลด
สัดส่วนอาจมีสิ่งต่อไปนี้:
export default { data () { return { animation_state: 'playing', animation_duration: 10, upload_filenames: [], upload_params: { target_directory: 'media', visibility: 'private', } } }, computed: { long_animation () { return this.animation_duration > 5; }, upload_requested () { return this.upload_filenames.length > 0; }, }, ... }
แนวทางดั้งเดิมในการจัดระเบียบโค้ดมีประโยชน์โดยส่วนใหญ่นักพัฒนาไม่ต้องกังวลว่าจะเขียนโค้ดชิ้นใหม่ได้ที่ไหน หากเรากำลังเพิ่มตัวแปรรีแอคทีฟให้แทรกใน data
มาตรา. หากเรากำลังมองหาตัวแปรที่มีอยู่เรารู้ว่าต้องอยู่ใน data
มาตรา.
วิธีการดั้งเดิมในการแบ่งการใช้งานฟังก์ชันออกเป็นส่วนต่างๆ (data
, computed
ฯลฯ ) ไม่เหมาะในทุกสถานการณ์
มักมีการอ้างถึงข้อยกเว้นต่อไปนี้:
Vue 2 (และ Vue 3 ที่เข้ากันได้แบบย้อนหลัง) นำเสนอวิธีแก้ปัญหาสำหรับการจัดระเบียบโค้ดส่วนใหญ่และปัญหาการนำกลับมาใช้ใหม่: มิกซ์อิน .
Mixins อนุญาตให้แยกฟังก์ชันการทำงานของส่วนประกอบในหน่วยรหัสแยกต่างหาก แต่ละฟังก์ชันจะถูกใส่ไว้ในมิกซ์อินที่แยกจากกันและทุกส่วนประกอบสามารถใช้มิกซ์อินได้ตั้งแต่หนึ่งรายการขึ้นไป ชิ้นส่วนที่กำหนดไว้ใน mixin สามารถใช้ในส่วนประกอบได้ราวกับว่าถูกกำหนดไว้ในส่วนประกอบเอง มิกซ์อินเป็นเหมือนคลาสในภาษาเชิงวัตถุที่รวบรวมโค้ดที่เกี่ยวข้องกับฟังก์ชันที่กำหนด เช่นเดียวกับคลาสมิกซ์อินสามารถสืบทอด (ใช้) ในหน่วยรหัสอื่นได้
อย่างไรก็ตามการให้เหตุผลกับมิกซ์อินนั้นยากกว่าเนื่องจากไม่เหมือนกับคลาสมิกซินไม่จำเป็นต้องออกแบบโดยคำนึงถึงการห่อหุ้ม Mixins ได้รับอนุญาตให้เป็นคอลเลกชันของโค้ดที่ถูกผูกไว้อย่างหลวม ๆ โดยไม่มีส่วนต่อประสานที่กำหนดไว้อย่างดีกับโลกภายนอก การใช้มิกซ์อินมากกว่าหนึ่งครั้งในส่วนประกอบเดียวกันอาจส่งผลให้ส่วนประกอบที่เข้าใจและใช้งานได้ยาก
ภาษาเชิงวัตถุส่วนใหญ่ (เช่น C # และ Java) กีดกันหรือแม้กระทั่งไม่อนุญาตให้สืบทอดหลายรายการแม้ว่ากระบวนทัศน์การเขียนโปรแกรมเชิงวัตถุจะมีเครื่องมือในการจัดการกับความซับซ้อนดังกล่าวก็ตาม (บางภาษาอนุญาตให้มีการสืบทอดหลายอย่างเช่น C ++ แต่การเรียบเรียงยังคงเป็นที่ต้องการมากกว่าการสืบทอด)
ปัญหาในทางปฏิบัติที่อาจเกิดขึ้นเมื่อใช้มิกซ์อินใน Vue คือ ชื่อชนกัน ซึ่งเกิดขึ้นเมื่อใช้ส่วนผสมสองตัวขึ้นไปประกาศชื่อสามัญ ควรสังเกตไว้ที่นี่ว่าหากกลยุทธ์เริ่มต้นของ Vue ในการจัดการกับการชนชื่อไม่เหมาะในสถานการณ์ที่กำหนดกลยุทธ์สามารถ ปรับ โดยนักพัฒนาสิ่งนี้มาพร้อมกับค่าใช้จ่ายในการแนะนำความซับซ้อนมากขึ้น
อีกประเด็นหนึ่งคือ mixins ไม่ได้นำเสนอสิ่งที่คล้ายกับตัวสร้างคลาส นี่เป็นปัญหาเพราะบ่อยครั้งที่เราต้องการฟังก์ชันการทำงานที่คล้ายกันมาก แต่ไม่ใช่ เหมือนเดิมทุกประการ, จะมีอยู่ในส่วนประกอบต่างๆ สิ่งนี้สามารถหลีกเลี่ยงได้ในบางกรณีง่ายๆด้วยการใช้ โรงงาน mixin .
ดังนั้นมิกซ์อินจึงไม่ใช่ทางออกที่ดีที่สุดสำหรับการจัดระเบียบโค้ดและการนำกลับมาใช้และยิ่งโปรเจ็กต์ใหญ่ขึ้นปัญหาก็จะยิ่งรุนแรงมากขึ้นเท่านั้น Vue 3 นำเสนอวิธีใหม่ในการแก้ปัญหาเดิมเกี่ยวกับการจัดระเบียบรหัสและการนำกลับมาใช้ใหม่
Composition API ช่วยให้เรา (แต่ทำ ไม่ ต้องการให้เรา) แยกชิ้นส่วนของส่วนประกอบออกอย่างสมบูรณ์ โค้ดทุกชิ้นไม่ว่าจะเป็นตัวแปรคุณสมบัติที่คำนวณได้นาฬิกา ฯลฯ สามารถกำหนดได้อย่างอิสระ
ตัวอย่างเช่นแทนที่จะมีวัตถุที่มี data
ส่วนที่มีคีย์ animation_state
ด้วยค่า (ค่าเริ่มต้น) 'กำลังเล่น' ตอนนี้เราสามารถเขียน (ที่ใดก็ได้ในโค้ด JavaScript ของเรา):
const animation_state = ref('playing');
ผลกระทบเกือบจะเหมือนกับการประกาศตัวแปรนี้ใน data
ส่วนของส่วนประกอบบางส่วน ข้อแตกต่างที่สำคัญประการเดียวคือเราต้องสร้าง ref
กำหนดไว้ภายนอกส่วนประกอบที่มีอยู่ในส่วนประกอบที่เราต้องการใช้ เราทำได้โดยการนำเข้าโมดูลไปยังตำแหน่งที่มีการกำหนดองค์ประกอบและส่งคืน ref
จาก setup
ส่วนของส่วนประกอบ เราจะข้ามขั้นตอนนี้ไปก่อนและเพียงแค่มุ่งเน้นไปที่ API ใหม่สักครู่ การเกิดปฏิกิริยาใน Vue 3 ไม่จำเป็นต้องมีส่วนประกอบ จริงๆแล้วมันเป็นระบบที่มีอยู่ในตัวเอง
เราสามารถใช้ตัวแปร animation_state
ใน ใด ๆ ขอบเขตที่เรานำเข้าตัวแปรนี้ไป หลังจากสร้าง ref
เราจะได้รับและกำหนดค่าจริงโดยใช้ ref.value
ตัวอย่างเช่น:
animation_state.value = 'paused'; console.log(animation_state.value);
เราต้องการคำต่อท้าย '.value' เนื่องจากตัวดำเนินการกำหนดจะกำหนดค่า (ไม่ตอบสนอง) 'หยุดชั่วคราว' ให้กับตัวแปร animation_state
การตอบสนองใน JavaScript (ทั้งเมื่อใช้งานผ่าน defineProperty
เช่นเดียวกับใน Vue 2 และเมื่ออิงตาม Proxy
เช่นเดียวกับใน Vue 3) ต้องการอ็อบเจ็กต์ที่มีคีย์ที่เราสามารถใช้งานได้ในเชิงโต้ตอบ
โปรดทราบว่านี่เป็นกรณีใน Vue 2 เช่นกัน ที่นั่นเรามีส่วนประกอบเป็นคำนำหน้าสำหรับสมาชิกข้อมูลที่ตอบสนอง (component.data_member
) เว้นแต่และจนกว่ามาตรฐานภาษา JavaScript จะแนะนำความสามารถในการโอเวอร์โหลดตัวดำเนินการกำหนดนิพจน์ปฏิกิริยาจะต้องใช้อ็อบเจ็กต์และคีย์ (เช่น animation_state
และ value
ตามด้านบน) จึงจะปรากฏทางด้านซ้ายมือ ของการดำเนินการมอบหมายใด ๆ ที่เราต้องการรักษาปฏิกิริยา
ในเทมเพลตเราสามารถละเว้น .value
เนื่องจาก Vue ต้องประมวลผลโค้ดเทมเพลตล่วงหน้าและสามารถตรวจจับการอ้างอิงโดยอัตโนมัติ:
.value
ในทางทฤษฎีคอมไพเลอร์ Vue สามารถประมวลผลส่วนของไฟล์ คอมโพเนนต์ไฟล์เดียว (SFC) ในทำนองเดียวกันการแทรก refs
ที่จำเป็น อย่างไรก็ตามการใช้ reactive
จากนั้นจะแตกต่างกันไปขึ้นอยู่กับว่าเราใช้ SFC หรือไม่ดังนั้นคุณสมบัติดังกล่าวอาจไม่เป็นที่ต้องการด้วยซ้ำ
บางครั้งเรามีเอนทิตี (เช่นเป็นวัตถุ Javascript หรืออาร์เรย์) ที่เราไม่เคยตั้งใจจะแทนที่ด้วยอินสแตนซ์ที่แตกต่างไปจากเดิมอย่างสิ้นเชิง แต่เราอาจสนใจเฉพาะการแก้ไขฟิลด์ที่คีย์เท่านั้น มีชวเลขในกรณีนี้: โดยใช้ ref
แทน .value
ช่วยให้เราสามารถแจกจ่าย const upload_params = reactive({ target_directory: 'media', visibility: 'private', }); upload_params.visibility = 'public'; // no `.value` needed here // if we did not make `upload_params` constant, the following code would compile but we would lose reactivity after the assignment; it is thus a good idea to make reactive variables ```const``` explicitly: upload_params = { target_directory: 'static', visibility: 'public', };
:
ref
ปฏิกิริยาแยกตัวด้วย reactive
และ Vue.observable
ไม่ใช่ฟีเจอร์ใหม่ทั้งหมดของ Vue 3 ซึ่งเป็นส่วนหนึ่ง แนะนำใน Vue 2.6 โดยที่อินสแตนซ์ข้อมูลรีแอกทีฟที่แยกออกมาดังกล่าวเรียกว่า 'สิ่งที่สังเกตได้' ส่วนใหญ่สามารถแทนที่ reactive
ด้วย Vue.observable
. ความแตกต่างประการหนึ่งคือการเข้าถึงและการกลายพันธุ์ของวัตถุที่ส่งไปยัง const x = ref(5); const x_squared = computed(() => x.value * x.value); console.log(x_squared.value); // outputs 25
โดยตรงคือปฏิกิริยาในขณะที่ API ใหม่ส่งกลับไฟล์ วัตถุพร็อกซี ดังนั้นการกลายพันธุ์วัตถุดั้งเดิมจะไม่มีผลปฏิกิริยา
สิ่งใหม่ทั้งหมดใน Vue 3 ก็คือตอนนี้ชิ้นส่วนปฏิกิริยาอื่น ๆ ของส่วนประกอบสามารถกำหนดได้อย่างอิสระเช่นกันนอกเหนือจากข้อมูลปฏิกิริยา คุณสมบัติที่คำนวณถูกนำไปใช้ในลักษณะที่คาดหวัง:
setup
ในทำนองเดียวกันสามารถใช้นาฬิกาประเภทต่างๆวิธีการตลอดอายุการใช้งานและการฉีดพึ่งพา เพื่อความรวดเร็วเราจะไม่กล่าวถึง เหล่านั้น ที่นี่.
สมมติว่าเราใช้แนวทาง SFC มาตรฐานในการพัฒนา Vue เราอาจใช้ API แบบเดิมโดยมีส่วนแยกต่างหากสำหรับข้อมูลคุณสมบัติที่คำนวณเป็นต้นเราจะรวมปฏิกิริยาเล็ก ๆ ของ Composition API กับ SFC ได้อย่างไร Vue 3 แนะนำส่วนอื่นสำหรับสิ่งนี้: created
. ส่วนใหม่สามารถคิดได้ว่าเป็นวิธีวงจรชีวิตใหม่ (ซึ่งดำเนินการก่อนฮุกอื่น ๆ โดยเฉพาะก่อนหน้า Squared: {{ x_squared }}, negative: {{ x_negative }} import { ref, computed } from 'vue'; export default { name: 'Demo', computed: { x_negative() { return -this.x; } }, setup() { const x = ref(0); const x_squared = computed(() => x.value * x.value); return {x, x_squared}; } }
)
นี่คือตัวอย่างของส่วนประกอบทั้งหมดที่รวมแนวทางดั้งเดิมเข้ากับ Composition API:
setup
สิ่งที่ควรหลีกเลี่ยงจากตัวอย่างนี้:
setup
คุณอาจต้องการสร้างไฟล์แยกต่างหากสำหรับแต่ละฟังก์ชันนำเข้าไฟล์นี้ใน SFC และส่งคืนบิตของปฏิกิริยาที่ต้องการจาก x
(เพื่อให้พร้อมใช้งานในส่วนที่เหลือของส่วนประกอบ).value
แม้ว่าจะเป็นการอ้างอิง แต่ก็ไม่จำเป็นต้องมี computed
เมื่ออ้างถึงในโค้ดเทมเพลตหรือในส่วนดั้งเดิมของส่วนประกอบเช่น raw_values
ในส่วนแรกของบทความนี้เราได้สัมผัสถึงแรงจูงใจมาตรฐานสำหรับ Composition API ซึ่งได้รับการปรับปรุงการจัดระเบียบโค้ดและการนำกลับมาใช้ใหม่ แท้จริงแล้วจุดขายหลักของ API ใหม่ไม่ใช่พลัง แต่เป็นความสะดวกสบายขององค์กรที่นำมาซึ่งความสามารถในการจัดโครงสร้างโค้ดให้ชัดเจนยิ่งขึ้น อาจดูเหมือนทั้งหมดนั่นคือ Composition API ช่วยให้สามารถใช้ส่วนประกอบที่หลีกเลี่ยงข้อ จำกัด ของโซลูชันที่มีอยู่แล้วเช่นมิกซ์อิน
อย่างไรก็ตาม API ใหม่ยังมีอีกมาก Composition API ไม่เพียง แต่ช่วยให้ระบบรีแอคทีฟมีการจัดระเบียบที่ดีขึ้นเท่านั้น ส่วนประกอบสำคัญคือความสามารถในการ แบบไดนามิก เพิ่มปฏิกิริยาให้กับแอปพลิเคชัน ก่อนหน้านี้เราต้องกำหนดข้อมูลทั้งหมดคุณสมบัติที่คำนวณทั้งหมด ฯลฯ ก่อนที่จะโหลดส่วนประกอบ เหตุใดการเพิ่มวัตถุที่มีปฏิกิริยาในระยะต่อมาจึงมีประโยชน์? ในสิ่งที่เหลืออยู่เรามาดูตัวอย่างที่ซับซ้อนมากขึ้น: สเปรดชีต
เครื่องมือสเปรดชีตเช่น Microsoft Excel, LibreOffice Calc และ Google ชีตล้วนมีระบบปฏิกิริยาบางประเภท เครื่องมือเหล่านี้นำเสนอผู้ใช้ด้วยตารางโดยมีคอลัมน์ที่จัดทำดัชนีโดย A – Z, AA – ZZ, AAA – ZZZ เป็นต้นและแถวที่จัดทำดัชนีเป็นตัวเลข
แต่ละเซลล์อาจมีค่าธรรมดาหรือสูตร เซลล์ที่มีสูตรเป็นคุณสมบัติที่คำนวณได้ซึ่งอาจขึ้นอยู่กับค่าหรือคุณสมบัติที่คำนวณอื่น ๆ ด้วยสเปรดชีตมาตรฐาน (และแตกต่างจากระบบการเกิดปฏิกิริยาใน Vue) คุณสมบัติที่คำนวณเหล่านี้ได้รับอนุญาตให้ขึ้นอยู่กับตัวมันเอง! การอ้างอิงตัวเองดังกล่าวมีประโยชน์ในบางสถานการณ์ที่ได้รับค่าที่ต้องการโดยการประมาณซ้ำ
ความแตกต่างระหว่าง บริษัท s และ c
เมื่อเนื้อหาของเซลล์เปลี่ยนแปลงเซลล์ทั้งหมดที่ขึ้นอยู่กับเซลล์นั้นจะเรียกการอัปเดต หากมีการเปลี่ยนแปลงเพิ่มเติมอาจมีการกำหนดเวลาอัปเดตเพิ่มเติม
หากเราจะสร้างแอปพลิเคชันสเปรดชีตด้วย Vue เป็นเรื่องปกติที่จะถามว่าเราสามารถนำระบบปฏิกิริยาของ Vue มาใช้และทำให้ Vue เป็นกลไกของแอปสเปรดชีตได้หรือไม่ สำหรับแต่ละเซลล์เราสามารถจำค่าดิบที่แก้ไขได้รวมทั้งค่าที่คำนวณได้ ค่าที่คำนวณจะแสดงถึงค่าดิบหากเป็นค่าธรรมดามิฉะนั้นค่าที่คำนวณจะเป็นผลมาจากนิพจน์ (สูตร) ที่เขียนแทนค่าธรรมดา
ด้วย Vue 2 วิธีใช้สเปรดชีตคือการมี computed_values
อาร์เรย์สองมิติของสตริงและ computed_values
อาร์เรย์สองมิติ (คำนวณ) ของค่าเซลล์
หากจำนวนเซลล์มีขนาดเล็กและคงที่ก่อนที่คอมโพเนนต์ Vue ที่เหมาะสมจะโหลดเราอาจมีค่าดิบหนึ่งค่าและค่าที่คำนวณได้หนึ่งค่าสำหรับทุกเซลล์ของตารางในนิยามองค์ประกอบของเรา นอกเหนือจากความเลวร้ายด้านสุนทรียศาสตร์ที่การใช้งานดังกล่าวอาจทำให้เกิดตารางที่มีจำนวนเซลล์คงที่ในเวลารวบรวมอาจไม่นับเป็นสเปรดชีต
มีปัญหากับอาร์เรย์สองมิติ A1
ด้วย คุณสมบัติที่คำนวณได้มักจะเป็นฟังก์ชันที่การประเมินผลในกรณีนี้ขึ้นอยู่กับตัวมันเอง (โดยทั่วไปการคำนวณค่าของเซลล์จะต้องใช้ค่าอื่น ๆ เพื่อคำนวณอยู่แล้ว) แม้ว่า Vue จะอนุญาตคุณสมบัติการคำนวณแบบอ้างอิงตัวเองการอัปเดตเซลล์เดียวจะทำให้เซลล์ทั้งหมดถูกคำนวณใหม่ (ไม่ว่าจะมีการอ้างอิงหรือไม่ก็ตาม) สิ่งนี้จะไร้ประสิทธิภาพอย่างยิ่ง ดังนั้นเราอาจต้องใช้ปฏิกิริยาในการตรวจจับการเปลี่ยนแปลงของข้อมูลดิบด้วย Vue 2 แต่ทุกอย่างอื่น ๆ ที่เกิดปฏิกิริยาจะต้องถูกนำมาใช้ตั้งแต่เริ่มต้น
ด้วย Vue 3 เราสามารถแนะนำคุณสมบัติการคำนวณใหม่สำหรับทุกเซลล์ หากตารางเติบโตขึ้นจะมีการนำคุณสมบัติที่คำนวณใหม่มาใช้
สมมติว่าเรามีเซลล์ A2
และ A2
และเราต้องการ A1
เพื่อแสดงสี่เหลี่ยมของ let A1 = computed(() => 5); let A2 = computed(() => A1.value * A1.value); console.log(A2.value); // outputs 25
ซึ่งมีค่าเป็นหมายเลข 5 ภาพร่างของสถานการณ์นี้:
A1
สมมติว่าเราอยู่ในสถานการณ์ง่ายๆนี้สักครู่ มีปัญหาที่นี่ จะเป็นอย่างไรหากเราต้องการเปลี่ยนแปลง A1 = computed(() => 6); console.log(A2.value); // outputs 25 if we already ran the code above
เพื่อให้มีหมายเลข 6? สมมติว่าเราเขียนสิ่งนี้:
A1
สิ่งนี้ไม่ได้เปลี่ยนแค่ค่า 5 ถึง 6 ใน A1
ตัวแปร A2
มีเอกลักษณ์ที่แตกต่างกันอย่างสิ้นเชิงในขณะนี้: คุณสมบัติที่คำนวณได้ซึ่งเปลี่ยนเป็นเลข 6 อย่างไรก็ตามตัวแปร A1
ยังคงตอบสนองต่อการเปลี่ยนแปลงข้อมูลประจำตัวเก่าของตัวแปร A2
ดังนั้น A1
ไม่ควรอ้างถึง A1
โดยตรง แต่เป็นวัตถุพิเศษบางอย่างที่มักจะพร้อมใช้งานในบริบทและจะบอกเราว่าคืออะไร A1
ในขณะนี้ กล่าวอีกนัยหนึ่งเราต้องมีระดับของทิศทางก่อนที่จะเข้าถึง pointer
บางอย่างเช่น ตัวชี้ . ไม่มีตัวชี้เป็นเอนทิตีชั้นหนึ่งใน Javascript แต่ง่ายต่อการจำลอง หากเราต้องการมี value
ชี้ไปที่ pointer = {points_to: value}
เราสามารถสร้างวัตถุ pointer.points_to
การเปลี่ยนทิศทางจำนวนตัวชี้เป็นการกำหนดให้กับ pointer.points_to
และการยกเลิกการอ้างอิง (การเข้าถึงค่าที่ชี้ไป) จำนวนเงินเพื่อดึงค่าของ let A1 = reactive({points_to: computed(() => 5)}); let A2 = reactive({points_to: computed(() => A1.points_to * A1.points_to)}); console.log(A2.points_to); // outputs 25
ในกรณีของเราเราดำเนินการดังนี้:
A1.points_to = computed(() => 6); console.log(A2.points_to); // outputs 36
ตอนนี้เราแทน 5 ด้วย 6 ได้
const cells = reactive([ computed(() => 5), computed(() => cells[0].value * cells[0].value) ]); cells[0] = computed(() => 6); console.log(cells[1].value); // outputs 36
บนเซิร์ฟเวอร์ Discord ของ Vue ผู้ใช้ redblobgames แนะนำแนวทางอื่นที่น่าสนใจ: แทนที่จะใช้ค่าจากการคำนวณให้ใช้การอ้างอิงที่รวมฟังก์ชันปกติ วิธีนี้เราสามารถสลับฟังก์ชันได้ในทำนองเดียวกันโดยไม่ต้องเปลี่ยนข้อมูลประจำตัวของข้อมูลอ้างอิง
การใช้งานสเปรดชีตของเราจะมีเซลล์ที่อ้างอิงโดยคีย์ของอาร์เรย์สองมิติ อาร์เรย์นี้สามารถให้ระดับของทิศทางที่เราต้องการ ดังนั้นในกรณีของเราเราไม่จำเป็นต้องมีการจำลองตัวชี้เพิ่มเติม เราสามารถมีอาร์เรย์หนึ่งตัวที่ไม่แยกความแตกต่างระหว่างค่าดิบและค่าที่คำนวณได้ ทุกอย่างสามารถเป็นค่าที่คำนวณได้:
const rows = ref(30), cols = ref(26); /* if a string codes a number, return the number, else return a string */ const as_number = raw_cell => /^[0-9]+(.[0-9]+)?$/.test(raw_cell) ? Number.parseFloat(raw_cell) : raw_cell; const make_table = (val = '', _rows = rows.value, _cols = cols.value) => Array(_rows).fill(null).map(() => Array(_cols).fill(val)); const raw_values = reactive(make_table('', rows.value, cols.value)); const computed_values = reactive(make_table(undefined, rows.value, cols.value)); /* a useful metric for debugging: how many times did cell (re)computations occur? */ const calculations = ref(0);
อย่างไรก็ตามเราต้องการแยกความแตกต่างของค่าดิบและค่าจากการคำนวณเนื่องจากเราต้องการให้สามารถผูกค่าดิบกับองค์ประกอบอินพุต HTML ได้ นอกจากนี้หากเรามีอาร์เรย์แยกต่างหากสำหรับค่าดิบเราจะไม่ต้องเปลี่ยนนิยามของคุณสมบัติที่คำนวณ พวกเขาจะอัปเดตโดยอัตโนมัติตามข้อมูลดิบ
เริ่มต้นด้วยคำจำกัดความพื้นฐานบางส่วนซึ่งส่วนใหญ่อธิบายได้ด้วยตนเอง
computed_values[row][column]
แผนนี้มีไว้สำหรับทุก raw_values[row][column]
ที่จะคำนวณได้ดังนี้ ถ้า =
ไม่ได้ขึ้นต้นด้วย raw_values[row][column]
, return const letters = Array(26).fill(0) .map((_, i) => String.fromCharCode('A'.charCodeAt(0) + i)); const transpile = str => { let cell_replacer = (match, prepend, col, row) => { col = letters.indexOf(col); row = Number.parseInt(row) - 1; return prepend + ` computed_values[${row}][${col}].value `; }; return str.replace(/(^|[^A-Z])([A-Z])([0-9]+)/g, cell_replacer); };
มิฉะนั้นให้แยกวิเคราะห์สูตรคอมไพล์เป็น JavaScript ประเมินโค้ดที่คอมไพล์แล้วส่งคืนค่า เพื่อให้สิ่งต่างๆสั้นลงเราจะโกงเล็กน้อยด้วยการแยกวิเคราะห์สูตรและเราจะไม่ทำการเพิ่มประสิทธิภาพที่ชัดเจนที่นี่เช่นแคชการคอมไพล์
เราจะถือว่าผู้ใช้สามารถป้อนนิพจน์ JavaScript ที่ถูกต้องเป็นสูตรได้ เราสามารถแทนที่การอ้างอิงชื่อเซลล์ที่ปรากฏในนิพจน์ของผู้ใช้เช่น A1, B5 เป็นต้นด้วยการอ้างอิงค่าเซลล์จริง (คำนวณ) ฟังก์ชันต่อไปนี้ทำหน้าที่นี้โดยสมมติว่าสตริงที่มีลักษณะคล้ายชื่อเซลล์จะระบุเซลล์เสมอ (และไม่ใช่ส่วนหนึ่งของนิพจน์ JavaScript ที่ไม่เกี่ยวข้อง) เพื่อความง่ายเราจะถือว่าดัชนีคอลัมน์ประกอบด้วยตัวอักษรตัวเดียว
transpile
การใช้ const computed_cell_generator = (i, j) => { const computed_cell = computed(() => { // we don't want Vue to think that the value of a computed_cell depends on the value of `calculations` nextTick(() => ++calculations.value); let raw_cell = raw_values[i][j].trim(); if (!raw_cell || raw_cell[0] != '=') return as_number(raw_cell); let user_code = raw_cell.substring(1); let code = transpile(user_code); try { // the constructor of a Function receives the body of a function as a string let fn = new Function(['computed_values'], `return ${code};`); return fn(computed_values); } catch (e) { return 'ERROR'; } }); return computed_cell; }; for (let i = 0; i
ขั้นตอนต่อไปคือการสร้างคุณสมบัติที่คำนวณสำหรับทุกเซลล์ ขั้นตอนนี้จะเกิดขึ้นครั้งเดียวในชีวิตของทุกเซลล์ เราสามารถสร้างโรงงานที่จะคืนค่าคุณสมบัติที่คำนวณได้ตามต้องการ:
setup
หากเราใส่รหัสทั้งหมดข้างต้นใน {raw_values, computed_values, rows, cols, letters, calculations}
วิธีการเราต้องกลับ Calculations: {{ calculations }}
import {ref, reactive, computed, watchEffect, toRefs, nextTick, onUpdated} from 'vue'; export default { name: 'App', components: {}, data() { return { ui_editing_i: null, ui_editing_j: null, } }, methods: { get_dom_input(i, j) { return this.$refs['input' + i + '-' + j]; }, activate(i, j) { this.ui_editing_i = i; this.ui_editing_j = j; nextTick(() => this.get_dom_input(i, j).focus()); }, active(i, j) { return this.ui_editing_i === i && this.ui_editing_j === j; }, unselect() { this.ui_editing_i = null; this.ui_editing_j = null; }, computed_value_formatter(str) if (str === undefined , ui_enter() { if (this.ui_editing_i {{ letters[j] }} {{ i + 1 }}
ด้านล่างนี้เรานำเสนอองค์ประกอบที่สมบูรณ์พร้อมด้วยอินเทอร์เฟซผู้ใช้พื้นฐาน
รหัสสามารถใช้ได้บน GitHub และคุณยังสามารถตรวจสอบไฟล์ การสาธิตสด .
report_data
เราได้เห็นว่าระบบปฏิกิริยาแบบแยกส่วนของ Vue 3 ไม่เพียงช่วยให้โค้ดสะอาดขึ้นเท่านั้น แต่ยังช่วยให้ระบบรีแอคทีฟที่ซับซ้อนขึ้นตามกลไกการเกิดปฏิกิริยาใหม่ของ Vue เวลาผ่านไปประมาณเจ็ดปีนับตั้งแต่มีการเปิดตัว Vue และการแสดงออกที่เพิ่มขึ้นอย่างชัดเจนนั้นไม่เป็นที่ต้องการอย่างมาก
ตัวอย่างสเปรดชีต เป็นการสาธิตอย่างตรงไปตรงมาว่า Vue สามารถทำอะไรได้บ้างและคุณยังสามารถตรวจสอบไฟล์ การสาธิตสด .
แต่ในตัวอย่างคำจริงมันค่อนข้างเฉพาะ ระบบใหม่อาจมีประโยชน์ในสถานการณ์ใดบ้าง? กรณีการใช้งานที่ชัดเจนที่สุดสำหรับการเกิดปฏิกิริยาตามความต้องการอาจเพิ่มประสิทธิภาพสำหรับการใช้งานที่ซับซ้อน
ในแอปพลิเคชันฟรอนต์เอนด์ที่ทำงานกับข้อมูลจำนวนมากค่าใช้จ่ายในการใช้ปฏิกิริยาตอบสนองต่อความคิดที่ไม่ดีอาจส่งผลเสียต่อประสิทธิภาพ สมมติว่าเรามีแอปพลิเคชันแผงควบคุมธุรกิจที่จัดทำรายงานเชิงโต้ตอบเกี่ยวกับกิจกรรมทางธุรกิจของ บริษัท ผู้ใช้สามารถเลือกช่วงเวลาและเพิ่มหรือลบตัวบ่งชี้ประสิทธิภาพในรายงาน ตัวบ่งชี้บางตัวอาจแสดงค่าที่ขึ้นอยู่กับตัวบ่งชี้อื่น ๆ
วิธีหนึ่งในการใช้การสร้างรายงานคือการใช้โครงสร้างเสาหิน เมื่อผู้ใช้เปลี่ยนพารามิเตอร์อินพุตในอินเทอร์เฟซคุณสมบัติที่คำนวณได้รายการเดียวเช่น
|_+_|จะได้รับการอัปเดต การคำนวณของคุณสมบัติที่คำนวณนี้เกิดขึ้นตามแผนแบบฮาร์ดโค้ดขั้นแรกคำนวณตัวบ่งชี้ประสิทธิภาพอิสระทั้งหมดจากนั้นจึงขึ้นอยู่กับตัวบ่งชี้อิสระเหล่านี้เท่านั้นเป็นต้น
การนำไปใช้งานที่ดีกว่าจะแยกส่วนของรายงานออกมาและคำนวณอย่างอิสระ มีประโยชน์บางประการสำหรับสิ่งนี้:
หากทราบตัวบ่งชี้ประสิทธิภาพทั้งหมดที่อาจเป็นส่วนหนึ่งของรายงานขั้นสุดท้ายก่อนที่ส่วนประกอบ Vue จะโหลดเราอาจสามารถใช้การแยกส่วนที่เสนอได้แม้จะใช้ Vue 2 มิฉะนั้นหากแบ็กเอนด์เป็นแหล่งเดียวของความจริง (ซึ่งก็คือ โดยปกติจะเป็นกรณีที่มีแอปพลิเคชันที่ขับเคลื่อนด้วยข้อมูล) หรือหากมีผู้ให้บริการข้อมูลภายนอกเราสามารถสร้างคุณสมบัติที่คำนวณตามความต้องการสำหรับรายงานทุกชิ้น
ขอบคุณ Vue 3 ตอนนี้ไม่เพียง แต่ทำได้ แต่ทำได้ง่าย
Vue 3 มีชื่อรหัสว่า 'One Piece' เป็นรุ่นล่าสุด
Vue 3 มีเสถียรภาพอย่างเป็นทางการ อย่างไรก็ตามในขณะที่เขียนตัวอย่างโค้ดที่นำเสนอในบทความนี้ฉันพบและรายงานปัญหาเล็กน้อยบางอย่าง
ใช่ในแง่ที่ว่าไม่ต้องการการเปลี่ยนแปลงที่สำคัญกับรหัสของคุณ อย่างไรก็ตามแอพจำนวนมากจะต้องมีการเปลี่ยนแปลงเล็กน้อย
Vue เปิดตัวสู่สาธารณะครั้งแรกในเดือนกุมภาพันธ์ 2014 Vue 1.0 เปิดตัวในเดือนตุลาคม 2015 และเวอร์ชันล่าสุด (Vue 3.0) เปิดตัวในเดือนกันยายน 2020