บทช่วยสอน AngularJS: ทำความเข้าใจคำสั่งแบบกำหนดเองให้ชัดเจน
เผยแพร่แล้ว: 2022-03-11ด้วยการเติบโตอย่างรวดเร็วของ JavaScript ในฐานะภาษาเต็มสแต็ก แอปพลิเคชันจำนวนมากขึ้นใช้เฟรมเวิร์กที่ช่วยให้เว็บเบราว์เซอร์จัดการการประมวลผล UI ได้มากขึ้น เช่น การผูกข้อมูล การจัดการมุมมองข้อมูล การแปลงข้อมูล และบริการอื่นๆ อีกมากมาย หนึ่งในเฟรมเวิร์กที่มีความสามารถ ขยายได้ และเป็นที่นิยมมากที่สุดคือ AngularJS และหนึ่งในองค์ประกอบที่มีประโยชน์ที่สุดของเฟรมเวิร์ก AngularJS คือสิ่งที่เรียกว่า directive AngularJS มีคำสั่งที่มีประโยชน์มากมาย และที่สำคัญกว่านั้นคือ มีกรอบงานที่สมบูรณ์สำหรับการสร้างคำสั่งแบบกำหนดเอง
คำสั่งคืออะไร? พูดง่ายๆ ก็คือ คำสั่งคือฟังก์ชัน JavaScript ที่จัดการและเพิ่มพฤติกรรมให้กับองค์ประกอบ HTML DOM คำสั่งอาจเรียบง่ายหรือซับซ้อนอย่างยิ่ง ดังนั้น การทำความเข้าใจตัวเลือกและฟังก์ชันมากมายที่จัดการกับตัวเลือกเหล่านี้จึงเป็นสิ่งสำคัญ
ในบทช่วยสอนนี้ ฟังก์ชันทั้งสี่ที่ดำเนินการเป็นคำสั่งจะถูกสร้างขึ้นและนำไปใช้กับ DOM จะถูกสำรวจและจะมีตัวอย่างให้ โพสต์นี้ถือว่ามีความคุ้นเคยกับ AngularJS และคำสั่งที่กำหนดเอง หากคุณเพิ่งเริ่มใช้ Angular คุณอาจสนุกกับบทช่วยสอนเกี่ยวกับการสร้างแอป AngularJS แอปแรกของคุณ
สี่ฟังก์ชันของวงจรชีวิตคำสั่ง AngularJS
มีตัวเลือกมากมายที่สามารถกำหนดค่าได้และวิธีที่ตัวเลือกเหล่านั้นเกี่ยวข้องกันเป็นสิ่งสำคัญ แต่ละคำสั่งผ่านบางสิ่งที่คล้ายกับวงจรชีวิตเมื่อ AngularJS รวบรวมและเชื่อมโยง DOM วงจรชีวิตของคำสั่งเริ่มต้นและสิ้นสุดภายในกระบวนการบูตสแตรปของ AngularJS ก่อนที่หน้าจะแสดงผล ในวงจรชีวิตของ directive มีฟังก์ชันที่แตกต่างกันสี่ฟังก์ชันที่สามารถดำเนินการได้หากมีการกำหนดไว้ แต่ละรายการช่วยให้นักพัฒนาสามารถควบคุมและปรับแต่งคำสั่งที่จุดต่างๆ ของวงจรชีวิตได้
สี่ฟังก์ชันได้แก่: คอมไพล์ คอนโทรลเลอร์ พรี ลิงก์ และ โพสต์ลิงก์
ฟังก์ชัน คอมไพล์ อนุญาตให้คำสั่งจัดการ DOM ก่อนที่จะคอมไพล์และเชื่อมโยง ดังนั้นจึงอนุญาตให้เพิ่ม/ลบ/เปลี่ยนคำสั่ง เช่นเดียวกับเพิ่ม/ลบ/เปลี่ยนองค์ประกอบ DOM อื่นๆ
ฟังก์ชัน ตัวควบคุม ช่วยอำนวยความสะดวกในการสื่อสารแบบสั่งการ คำสั่งพี่น้องและเด็กสามารถขอให้ผู้ควบคุมพี่น้องและผู้ปกครองสื่อสารข้อมูลได้
ฟังก์ชัน ลิงก์ล่วงหน้า ช่วยให้สามารถจัดการ ขอบเขต $ ส่วนตัวได้ก่อนที่กระบวนการโพสต์ลิงก์จะเริ่มขึ้น
วิธี โพสต์ลิงก์ เป็นวิธีหลักในการดำเนินการตามคำสั่ง
ในคำสั่งนี้ การจัดการ DOM หลังการคอมไพล์จะเกิดขึ้น มีการกำหนดค่าตัวจัดการเหตุการณ์ เช่นเดียวกับนาฬิกาและสิ่งอื่น ๆ ในการประกาศคำสั่ง ฟังก์ชันทั้งสี่ถูกกำหนดดังนี้
.directive("directiveName",function () { return { controller: function() { // controller code here... }, compile: { // compile code here... return { pre: function() { // pre-link code here... }, post: function() { // post-link code here... } }; } } })
โดยทั่วไป ไม่จำเป็นต้องใช้ฟังก์ชันทั้งหมด ในกรณีส่วนใหญ่ นักพัฒนามักจะสร้าง ตัวควบคุม และฟังก์ชัน โพสต์ลิงก์ ตามรูปแบบด้านล่าง
.directive("directiveName",function () { return { controller: function() { // controller code here... }, link: function() { // post-link code here... } } })
ในการกำหนดค่านี้ ลิงก์ หมายถึงฟังก์ชัน โพสต์ลิงก์
ไม่ว่าจะกำหนดฟังก์ชันทั้งหมดหรือบางส่วน ลำดับการดำเนินการมีความสำคัญ โดยเฉพาะอย่างยิ่งการดำเนินการสัมพันธ์กับส่วนที่เหลือของแอปพลิเคชัน AngularJS
การดำเนินการฟังก์ชัน Directive ของ AngularJS สัมพันธ์กับคำสั่งอื่นๆ
พิจารณาข้อมูลโค้ด HTML ต่อไปนี้ที่มีคำสั่ง parentDir , childDir และ grandChildDir ที่ใช้กับส่วนย่อยของ HTML
<div parentDir> <div childDir> <div grandChildDir> </div> </div> </div>
ลำดับการดำเนินการของฟังก์ชันภายในคำสั่ง และสัมพันธ์กับคำสั่งอื่นๆ มีดังนี้:
- รวบรวมเฟส
- ฟังก์ชันคอมไพล์ : parentDir
- ฟังก์ชันคอมไพล์ : childDir
- ฟังก์ชันคอมไพล์ : grandChildDir
- คอนโทรลเลอร์ & เฟสพรีลิงค์
- ฟังก์ชันควบคุม : parentDir
- ฟังก์ชันพรีลิงค์ : parentDir
- ฟังก์ชันควบคุม : childDir
- ฟังก์ชันพรีลิงค์ : childDir
- ฟังก์ชันควบคุม : grandChildDir
- ฟังก์ชันพรีลิงก์ : grandChildDir
- โพสต์ลิงค์เฟส
- ฟังก์ชันโพสต์ลิงค์ : grandChildDir
- ฟังก์ชันโพสต์ลิงค์ : childDir
- ฟังก์ชันโพสต์ลิงค์ : parentDir
คำอธิบายฟังก์ชันคำสั่ง AngularJS: Deep Dive
ขั้นตอนการคอมไพล์จะเกิดขึ้นก่อน โดยพื้นฐานแล้ว ขั้นตอนการคอมไพล์จะแนบฟังเหตุการณ์เข้ากับองค์ประกอบ DOM ตัวอย่างเช่น หากองค์ประกอบ DOM เฉพาะถูกผูกไว้กับคุณสมบัติ $scope ตัวฟังเหตุการณ์ที่อนุญาตให้อัปเดตด้วยค่าของคุณสมบัติ $scope จะถูกนำไปใช้กับองค์ประกอบ DOM กระบวนการคอมไพล์เริ่มต้นด้วยองค์ประกอบ DOM รูทซึ่งแอปพลิเคชัน AngularJS ถูกบูทสแตรปและสำรวจกิ่งก้านของ DOM โดยใช้การข้ามผ่านครั้งแรกในเชิงลึก รวบรวมพาเรนต์ก่อน จากนั้นลูกๆ ของมันไปจนถึงโหนดปลายสุด
เมื่อการคอมไพล์เสร็จสิ้นแล้ว จะไม่สามารถเพิ่มหรือลบ directives ออกจาก DOM ได้อีกต่อไป (แม้ว่าจะมีวิธีแก้ไขโดยการใช้บริการคอมไพล์โดยตรง ขั้นตอนต่อไปคือการเรียกคอนโทรลเลอร์และฟังก์ชันพรีลิงก์สำหรับคำสั่งทั้งหมด เมื่อคอนโทรลเลอร์ เรียกว่า $scope ใช้ได้และสามารถใช้ได้ $element ที่ ฉีดเข้าไปในคอนโทรลเลอร์มีเทมเพลตที่คอมไพล์แต่ไม่รวมเนื้อหาย่อยที่คัดลอกมา นำไปใช้) ตามคำจำกัดความ ตัวควบคุมในรูปแบบ MVC เพียงแค่ส่งแบบจำลองไปยังมุมมองและกำหนดฟังก์ชันสำหรับจัดการเหตุการณ์ ดังนั้น ผู้ควบคุมของคำสั่งไม่ควรแก้ไข DOM ของคำสั่งด้วยเหตุผลสองประการ: มันละเมิดวัตถุประสงค์ของ controller และไม่ได้เพิ่มเนื้อหาย่อยที่แยกออกมาใน DOM แล้ว controller ทำอะไรนอกเหนือจากการปรับเปลี่ยน ขอบเขต $ ตัวควบคุมอนุญาตให้มีคำสั่งย่อยในการสื่อสาร wi คำสั่งหลัก ฟังก์ชันคอนโทรลเลอร์ควรถูกมองว่าเป็นอ็อบเจ็กต์ตัวควบคุมที่จะถูกส่งต่อไปยังฟังก์ชันโพสต์ลิงก์ของคำสั่งย่อย หากคำสั่งย่อยร้องขอ ดังนั้น ตัวควบคุมมักใช้เพื่ออำนวยความสะดวกในการสื่อสารแบบ directive โดยการสร้างอ็อบเจ็กต์ที่มีคุณสมบัติและวิธีการที่สามารถใช้ได้โดยคำสั่งย่อยและคำสั่งย่อย คำสั่งหลักไม่สามารถระบุได้ว่าคำสั่งย่อยสามารถกำหนดให้ใช้ตัวควบคุมได้หรือไม่ ดังนั้นจึงเป็นการดีที่สุดที่จะจำกัดโค้ดในวิธีนี้ไว้ที่ฟังก์ชันและคุณสมบัติที่สามารถใช้โดยคำสั่งย่อยได้อย่างปลอดภัย
หลังจากฟังก์ชันคอนโทรลเลอร์ ฟังก์ชันพรีลิงก์จะทำงาน ฟังก์ชั่นพรีลิงค์นั้นลึกลับสำหรับผู้คนจำนวนมาก หากคุณอ่านเอกสารจำนวนมากบนอินเทอร์เน็ตและในหนังสือ ผู้คนมักเขียนว่าฟังก์ชันนี้ใช้เฉพาะในสถานการณ์ที่หายากเท่านั้น และแทบทุกคนจะไม่ต้องการมันเลย คำอธิบายเดียวกันนั้นล้มเหลวในการยกตัวอย่างสถานการณ์ที่สามารถนำมาใช้ได้

ฟังก์ชันพรีลิงก์ไม่ได้ซับซ้อนเลยจริงๆ อันดับแรก หากคุณตรวจสอบซอร์สโค้ดของ AngularJS คุณจะพบตัวอย่างที่ยอดเยี่ยมของฟังก์ชันพรีลิงก์: คำสั่ง ng-init ใช้คำสั่งนี้ ทำไม? เป็นวิธีที่ยอดเยี่ยมในการรันโค้ดส่วนตัวที่เกี่ยวข้องกับ $scope ; รหัสที่ไม่สามารถเรียกโดยคำสั่งพี่และลูก ฟังก์ชันพรีลิงก์จะไม่ส่งผ่านไปยังคำสั่งต่างจากฟังก์ชันคอนโทรลเลอร์ ดังนั้นจึงสามารถใช้เพื่อรันโค้ดที่แก้ไข ขอบเขต $ ของคำสั่งได้ คำสั่ง ng-init ทำสิ่งนี้อย่างแน่นอน เมื่อฟังก์ชันลิงก์ล่วงหน้าสำหรับ ng-init ทำงาน มันจะเรียกใช้งาน JavaScript ที่ส่งผ่านไปยังคำสั่งโดยเทียบกับ $scope ของ directive ผลลัพธ์ของการดำเนินการสามารถดูได้ผ่านการสืบทอดต้นแบบของ ขอบเขต $scope ไปยังคำสั่งย่อยในระหว่างการดำเนินการของฟังก์ชันคอนโทรลเลอร์ พรีลิงก์ และโพสต์ลิงก์ แต่ไม่อนุญาตให้เข้าถึงคำสั่งย่อยเหล่านั้นเพื่อรันโค้ดอีกครั้งในคำสั่งก่อนหน้าของพาเรนต์ ฟังก์ชั่นการเชื่อมโยง นอกจากนี้ ไดเร็กทีฟอาจต้องรันโค้ดอื่นที่ไม่เกี่ยวข้องกับ ขอบเขต $ ที่ต้องการเก็บไว้เป็นส่วนตัว
นักพัฒนา AngularJS ที่มีประสบการณ์บางคนจะบอกว่ารหัส ส่วนตัว นี้ยังสามารถวางในคอนโทรลเลอร์ได้และไม่ถูกเรียกโดยคำสั่งย่อย อาร์กิวเมนต์นั้นจะเป็นจริงหากคำสั่งนั้นถูกใช้โดยผู้พัฒนาดั้งเดิมที่เขียนโค้ดนั้นเท่านั้น แต่ถ้าคำสั่งนั้นจะถูกแจกจ่ายและนำกลับมาใช้ใหม่โดยนักพัฒนารายอื่น การห่อหุ้มโค้ดส่วนตัวในฟังก์ชันพรีลิงก์อาจมีประโยชน์มาก เนื่องจากนักพัฒนาไม่เคยรู้ว่าคำสั่งของพวกเขาจะถูกนำกลับมาใช้ใหม่อย่างไรในช่วงเวลาหนึ่ง การปกป้องรหัสส่วนตัวจากการถูกเรียกใช้งานโดยคำสั่งย่อยจึงเป็นแนวทางที่ดีในการห่อหุ้มโค้ดคำสั่ง ฉันคิดว่าควรวางโค้ดสาธารณะสำหรับการสื่อสารแบบสั่งในฟังก์ชันคอนโทรลเลอร์ และโค้ดส่วนตัวในฟังก์ชันพรีลิงก์ เช่นเดียวกับตัวควบคุม ลิงก์ล่วงหน้าไม่ควรทำการจัดการ DOM หรือเรียกใช้ฟังก์ชัน transclude เนื่องจากเนื้อหาสำหรับคำสั่งย่อยยังไม่ได้เชื่อมโยง
สำหรับแต่ละคำสั่ง ตัวควบคุมและฟังก์ชันพรีลิงก์จะทำงานก่อนตัวควบคุมและฟังก์ชันพรีลิงก์ของคำสั่งย่อย เมื่อตัวควบคุมและเฟสพรีลิงก์สำหรับคำสั่งทั้งหมดเสร็จสมบูรณ์แล้ว AngularJS จะเริ่มเฟสการเชื่อมโยง และดำเนินการฟังก์ชันโพสต์ลิงก์สำหรับแต่ละคำสั่ง เฟสการเชื่อมโยงทำงานตรงข้ามกับการคอมไพล์ คอนโทรลเลอร์ และโฟลว์การดำเนินการพรีลิงก์ โดยเริ่มจากโหนดลีฟ DOM และทำงานจนถึงโหนดรูท DOM การข้ามผ่าน DOM ของโพสต์ลิงก์เป็นไปตามเส้นทางที่มีความลึกเป็นอันดับแรก เมื่อลิงก์คำสั่งย่อยแต่ละรายการ ฟังก์ชันโพสต์ลิงก์จะถูกดำเนินการ
ฟังก์ชัน post-link เป็นฟังก์ชันที่ใช้งานบ่อยที่สุดในคำสั่ง AngularJS ที่กำหนดเอง ในฟังก์ชันนี้ เกือบทุกอย่างที่สมเหตุสมผลสามารถทำได้ DOM สามารถจัดการได้ (สำหรับตัวมันเองและองค์ประกอบย่อยเท่านั้น) มี ขอบเขต $ วัตถุตัวควบคุมสำหรับคำสั่งหลักสามารถใช้ได้ ฟังก์ชันการถอดรหัสสามารถเรียกใช้ได้ ฯลฯ อย่างไรก็ตาม มีข้อจำกัดบางประการ ไม่สามารถเพิ่มคำสั่งใหม่ลงใน DOM ได้ เนื่องจากจะไม่มีการคอมไพล์ นอกจากนี้ การจัดการ DOM ทั้งหมดต้องทำโดยใช้ฟังก์ชัน DOM เพียงแค่เรียกใช้ฟังก์ชัน html บนองค์ประกอบ DOM และการส่งผ่าน HTML ใหม่จะเป็นการลบตัวจัดการเหตุการณ์ทั้งหมดที่เพิ่มเข้ามาในระหว่างกระบวนการคอมไพล์ ตัวอย่างเช่น สิ่งเหล่านี้จะไม่ทำงานตามที่คาดไว้:
element.html(element.html());
หรือ
element.html(element.html() + "<div>new content</div>");
รหัสจะไม่ทำให้ HTML เปลี่ยนแปลง แต่การกำหนดเวอร์ชันสตริงขององค์ประกอบ DOM ใหม่จะลบตัวจัดการเหตุการณ์ทั้งหมดที่สร้างขึ้นระหว่างกระบวนการคอมไพล์ โดยทั่วไป ฟังก์ชันโพสต์ลิงก์จะใช้เพื่อเชื่อมโยงตัวจัดการเหตุการณ์ $watch es และ $observe s
เมื่อดำเนินการฟังก์ชันโพสต์ลิงก์ทั้งหมดแล้ว ขอบเขต $ จะถูกนำไปใช้กับโครงสร้าง DOM ที่คอมไพล์และเชื่อมโยง และหน้า AngularJS จะพร้อมใช้งาน
แผนภูมิฟังก์ชันคำสั่ง
ต่อไปนี้คือแผนภูมิที่แสดงวัตถุประสงค์ของแต่ละฟังก์ชัน สิ่งที่ใช้ได้เมื่อดำเนินการ และแนวทางปฏิบัติที่ดีที่สุดในการใช้แต่ละฟังก์ชันอย่างเหมาะสม
การดำเนินการ คำสั่ง | คำสั่ง การทำงาน | โดม | แปล | $ขอบเขต | โทรได้ โดย เด็ก |
---|---|---|---|---|---|
1 | รวบรวม | ไม่ได้รวบรวม DOM แต่มีการโหลดเทมเพลตลงในพื้นที่เนื้อหาองค์ประกอบ DOM สามารถเพิ่มและลบคำสั่งได้ DOM สามารถจัดการได้ด้วยทั้งฟังก์ชัน DOM และการแทนที่สตริง HTML | ฟังก์ชัน Transclude ใช้งานได้แต่เลิกใช้งานแล้วและไม่ควรเรียกใช้ | ไม่พร้อมใช้งาน | ไม่สามารถเรียกใช้ฟังก์ชันโดยองค์ประกอบย่อย |
2 | ตัวควบคุม | องค์ประกอบ DOM ที่คอมไพล์แล้วพร้อมใช้งาน แต่ไม่ควรแก้ไข ยังไม่ได้เพิ่มเนื้อหาย่อยที่คัดแยกไปยังองค์ประกอบ DOM ไม่ควรมีการเปลี่ยนแปลง DOM เนื่องจากเป็นตัวควบคุมและยังไม่ได้เชื่อมโยงเนื้อหาย่อยที่คัดมา | ฟังก์ชัน Transclude ใช้งานได้ แต่ไม่ควรเรียกใช้ | ขอบเขต $ สามารถใช้ได้และสามารถใช้ได้ พารามิเตอร์ของฟังก์ชันถูกฉีดโดยใช้บริการ $injector | ฟังก์ชันถูกส่งผ่านไปยังฟังก์ชันลิงก์คำสั่งย่อยและสามารถเรียกใช้งานได้ |
3 | ลิงค์ล่วงหน้า | องค์ประกอบ DOM ที่คอมไพล์แล้วใช้ได้ แต่ไม่ควรแก้ไข เนื่องจากองค์ประกอบ DOM คำสั่งย่อยยังไม่ได้เชื่อมโยง | ฟังก์ชัน Transclude ใช้งานได้ แต่ไม่ควรเรียกใช้ | ขอบเขต $ สามารถใช้ได้และสามารถแก้ไขได้ | ฟังก์ชันไม่สามารถเรียกใช้โดยคำสั่งย่อย แต่อาจเรียกผู้ควบคุมคำสั่งของผู้ปกครอง |
4 | โพสต์ลิงค์ | องค์ประกอบ DOM ที่คอมไพล์แล้วและองค์ประกอบ DOM คำสั่งย่อยพร้อมใช้งาน DOM สามารถแก้ไขได้ด้วยฟังก์ชัน DOM เท่านั้น (ไม่มีการแทนที่ HTML) และสามารถเพิ่มได้เฉพาะเนื้อหาที่ไม่ต้องการการคอมไพล์เท่านั้น ไม่อนุญาตให้เพิ่ม/ลบคำสั่ง | ฟังก์ชัน Transclude สามารถใช้ได้และอาจเรียกได้ว่า | ขอบเขต $ สามารถใช้ได้และอาจใช้ | ไม่สามารถเรียกโดย directive children แต่อาจเรียกผู้ควบคุมของ parent directives |
สรุป
ในบทช่วยสอนเกี่ยวกับคำสั่ง AngularJS เราได้เรียนรู้เกี่ยวกับวัตถุประสงค์ ลำดับการดำเนินการ และความสามารถโดยรวม และการใช้งานสำหรับฟังก์ชันคำสั่งแต่ละฟังก์ชันจากทั้งหมด 4 ฟังก์ชัน ได้แก่ คอมไพล์ คอนโทรลเลอร์ พรี ลิงก์ และ โพสต์ลิงก์ จากสี่ฟังก์ชัน ตัวควบคุมและโพสต์ลิงก์เป็นฟังก์ชันที่ใช้บ่อยที่สุด แต่สำหรับคำสั่งที่ซับซ้อนมากขึ้นซึ่งจำเป็นต้องมีการควบคุม DOM ที่มากขึ้น หรือต้องการสภาพแวดล้อมการดำเนินการขอบเขตส่วนตัว สามารถใช้ฟังก์ชันคอมไพล์และลิงก์ล่วงหน้าได้