บทช่วยสอน 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 - ลำดับการดำเนินการที่สัมพันธ์กับคำสั่งอื่นๆ

คำอธิบายฟังก์ชันคำสั่ง 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 ที่มากขึ้น หรือต้องการสภาพแวดล้อมการดำเนินการขอบเขตส่วนตัว สามารถใช้ฟังก์ชันคอมไพล์และลิงก์ล่วงหน้าได้