JS เชิงมุม: อะไรคือความต้องการของฟังก์ชั่นลิงค์ของคำสั่งเมื่อเรามีคอนโทรลเลอร์ที่มีขอบเขตอยู่แล้ว?


199

ฉันจำเป็นต้องดำเนินการบางอย่างเกี่ยวกับขอบเขตและแม่แบบ ดูเหมือนว่าฉันสามารถทำได้ทั้งในlinkฟังก์ชั่นหรือcontrollerฟังก์ชั่น (เนื่องจากทั้งสองมีการเข้าถึงขอบเขต)

เมื่อไรฉันจึงต้องใช้linkฟังก์ชั่นไม่ใช่คอนโทรลเลอร์?

angular.module('myApp').directive('abc', function($timeout) {
    return {
        restrict: 'EA',
        replace: true,
        transclude: true,
        scope: true,
        link: function(scope, elem, attr) { /* link function */ },
        controller: function($scope, $element) { /* controller function */ }
    };
}

นอกจากนี้ฉันเข้าใจว่าlinkเป็นโลกที่ไม่ใช่เชิงมุม ดังนั้นฉันสามารถใช้$watch, และ$digest$apply

อะไรคือความสำคัญของlinkฟังก์ชั่นเมื่อเรามีคอนโทรลเลอร์อยู่แล้ว?


9
คุณหมายถึงอะไรด้วย " นอกจากนี้ผมเข้าใจการเชื่อมโยงที่เป็นโลกที่ไม่เชิงมุม. ดังนั้นฉันสามารถใช้$watch, $digestและ$apply. "?
musically_ut

2
ข้างในlinkเราไม่เห็นเวทย์มนตร์เชิงมุม เช่นไม่มีการผูกสองทาง ฯลฯ เพียงแค่เรามี API ของมุมที่ใช้งาน
Yugal Jindle

คำตอบ:


299

หลังจากที่ฉันเริ่มต้นการต่อสู้กับlinkและcontrollerฟังก์ชั่นและการอ่านค่อนข้างมากเกี่ยวกับพวกเขาผมคิดว่าตอนนี้ผมมีคำตอบ

แรกให้เข้าใจ ,

คำสั่งเชิงมุมทำงานอย่างไรโดยสรุป:

  • เราเริ่มต้นด้วยแม่แบบ (เป็นสตริงหรือโหลดเป็นสตริง)

    var templateString = '<div my-directive>{{5 + 10}}</div>';

  • ทีนี้นี่templateStringถูกห่อเป็นองค์ประกอบมุม

    var el = angular.element(templateString);

  • ด้วยelตอนนี้เรารวบรวมมัน$compileเพื่อกลับไปที่ฟังก์ชั่นลิงค์

    var l = $compile(el)

    นี่คือสิ่งที่เกิดขึ้น

    • $compile เดินผ่านเทมเพลตทั้งหมดและรวบรวมคำสั่งทั้งหมดที่จำได้
    • คำสั่งทั้งหมดที่ค้นพบจะถูกรวบรวมซ้ำและlinkฟังก์ชั่นของพวกเขาจะถูกรวบรวม
    • จากนั้นทุกlinkฟังก์ชั่นในห่อใหม่ฟังก์ชั่นและกลับมาเป็นlinkl
  • ในที่สุดเรามีscopeฟังก์ชั่นให้กับฟังก์ชั่นนี้l(ลิงค์) ซึ่งดำเนินการเพิ่มเติมฟังก์ชั่นการเชื่อมโยงห่อกับนี้scopeและองค์ประกอบที่เกี่ยวข้อง

    l(scope)

  • นี่เป็นการเพิ่มtemplateโหนดใหม่ให้กับDOMและเรียกใช้controllerซึ่งเพิ่มการเฝ้าดูในขอบเขตที่แบ่งใช้กับเทมเพลตใน DOM

ป้อนคำอธิบายรูปภาพที่นี่

การเปรียบเทียบคอมไพล์ vs ลิงค์เทียบกับคอนโทรลเลอร์ :

  • ทุกคำสั่งถูกรวบรวมเพียงครั้งเดียวและฟังก์ชั่นการเชื่อมโยงจะถูกเก็บไว้เพื่อนำมาใช้ใหม่ ดังนั้นหากมีบางสิ่งที่เกี่ยวข้องกับอินสแตนซ์ทั้งหมดของคำสั่งควรดำเนินการภายในcompileฟังก์ชันของคำสั่ง

  • ตอนนี้หลังจากที่รวบรวมเรามีlinkฟังก์ชั่นซึ่งจะถูกดำเนินการในขณะที่ติดแม่แบบให้กับDOM ดังนั้นเราจึงดำเนินการทุกอย่างที่เฉพาะเจาะจงกับทุก ๆ คำสั่ง สำหรับเช่น: ติดเหตุการณ์ , กรรมวิธีแม่แบบขึ้นอยู่กับขอบเขตฯลฯ

  • ในที่สุดคอนโทรลเลอร์จะต้องพร้อมใช้งานเพื่อให้สามารถใช้งานได้จริงและโต้ตอบในขณะที่คำสั่งทำงานบนDOM(หลังจากได้รับการเชื่อมต่อ) ดังนั้น:

    (1) หลังจากตั้งค่ามุมมอง [ V ] (เช่นเทมเพลต) พร้อมลิงก์ $scopeคือ [ M ] $controllerของเราและเป็น [ C ] ในMVC

    (2) ใช้ประโยชน์จากการรวม2 ทางกับ$ scopeโดยการตั้งค่านาฬิกา

    (3) $scopeคาดว่าจะมีการเพิ่มนาฬิกาในตัวควบคุมเนื่องจากนี่คือสิ่งที่ดูเทมเพลตในช่วงเวลาทำงาน

    (4) ในที่สุดcontrollerก็ใช้เพื่อให้สามารถสื่อสารระหว่างคำสั่งที่เกี่ยวข้อง (เหมือนmyTabsตัวอย่างในhttps://docs.angularjs.org/guide/directive )

    (5) มันเป็นความจริงที่เราจะได้ทำทั้งหมดนี้ในlinkฟังก์ชั่นเช่นกัน แต่เกี่ยวกับการแยกของความกังวล

ดังนั้นในที่สุดเราจึงมีสิ่งต่อไปนี้ที่เหมาะกับทุกชิ้นอย่างสมบูรณ์แบบ:

ป้อนคำอธิบายรูปภาพที่นี่


5
ฉันได้พบบทความนี้มีประโยชน์สำหรับการทำความเข้าใจกับคำสั่งของการดำเนินการที่นี่: nitty-gritty ของการรวบรวมและฟังก์ชั่นการเชื่อมโยงภายในคำสั่ง AngularJS
BobbyA

4
คำอธิบายที่ดี ต้องการที่จะพูดถึงว่าตัวควบคุมที่ได้รับการเรียกก่อนหน้าที่การเชื่อมโยง
jsbisht

38
ควบคุมจะดำเนินการก่อนที่จะเชื่อมโยง
Royi Namir

10
มันทำให้ฉันโมโหที่ Stack Overflow เรียกร้องให้มีการแก้ไขอย่างน้อย 6 ตัวอักษรดังนั้นจึงไม่อนุญาตให้ฉันแก้ไขการสะกดคำให้ในคำตอบนี้
user1886323

79

ทำไมต้องมีคอนโทรลเลอร์

ความแตกต่างระหว่างlinkและcontrollerเข้ามาเล่นเมื่อคุณต้องการซ้อนคำสั่งใน DOM ของคุณและแสดงฟังก์ชั่น API จากคำสั่งหลักกับคำสั่งซ้อน

จากเอกสาร :

วิธีปฏิบัติที่ดีที่สุด: ใช้คอนโทรลเลอร์เมื่อคุณต้องการเปิดเผย API ไปยังคำสั่งอื่น มิฉะนั้นใช้ลิงค์

สมมติว่าคุณต้องการที่จะมีสองแนวทางmy-formและmy-text-inputและคุณต้องการmy-text-inputสั่งจะปรากฏเฉพาะภายในmy-formและไม่มีที่อื่น

ในกรณีที่คุณจะพูดในขณะที่การกำหนดคำสั่งmy-text-inputว่าจะต้องมีการควบคุมจากที่parentองค์ประกอบ DOM require: '^myForm'ใช้จำเป็นต้องมีการโต้แย้งเช่นนี้ ตอนนี้ควบคุมจากองค์ประกอบหลักที่จะinjectedเข้าสู่ฟังก์ชั่นเป็นอาร์กิวเมนต์ที่สี่ต่อไปนี้link $scope, element, attributesคุณสามารถเรียกใช้ฟังก์ชั่นในคอนโทรลเลอร์นั้นและสื่อสารกับไดเรกทีฟหลัก

ยิ่งไปกว่านั้นหากไม่พบตัวควบคุมดังกล่าวจะเกิดข้อผิดพลาดขึ้น

ทำไมต้องใช้ลิงค์เลย

ไม่มีความจำเป็นที่แท้จริงในการใช้เป็นlinkฟังก์ชั่นหากมีการกำหนดcontrollerนับตั้งแต่ที่มีอยู่ใน$scope controllerยิ่งไปกว่านั้นในขณะที่การกำหนดทั้งสองlinkและcontrollerอย่างใดอย่างหนึ่งจะต้องระมัดระวังเกี่ยวกับลำดับของการภาวนาของทั้งสอง ( controllerจะดำเนินการก่อน)

อย่างไรก็ตามในการรักษาด้วยวิธีเชิงมุมส่วนใหญ่จัดการ DOM และ 2 ทางที่มีผลผูกพันใช้$watchersมักจะทำในlinkฟังก์ชั่นในขณะที่ API สำหรับเด็กและการจัดการจะทำใน$scope controllerนี่ไม่ใช่กฎที่ยากและรวดเร็ว แต่การทำเช่นนั้นจะทำให้รหัสเป็นแบบแยกส่วนและช่วยในการแยกความกังวล (คอนโทรลเลอร์จะรักษาdirectiveสถานะและlinkฟังก์ชั่นจะรักษาDOM+ การเชื่อมโยงภายนอก)


เยี่ยมมาก ตอนนี้คุณสามารถช่วยฉันด้วยส่วนที่สองของคำถาม?
Yugal Jindle

ฉันหมายถึงเนื่องจากเรามีตัวควบคุมที่มีอยู่ซึ่งอาจถูกใช้เพื่อสื่อสารกับคำสั่งอื่น ๆ ดังนั้นสิ่งที่ต้องการlinkคืออะไร?
Yugal Jindle

1
คำตอบของคุณไม่ตอบคำถามจริง
Yugal Jindle

1
มีปัญหาใด ๆ ที่เกิดขึ้นเมื่อเรากำหนดcontroller? เหตุใดฉันจึงต้องการคิดค้นฟังก์ชันใหม่ทั้งหมดเพื่อหลีกเลี่ยงการกำหนดคอนโทรลเลอร์
Yugal Jindle

1
ดูเหมือนว่า @scalaGirl s Link จะไม่ทำงานอีกต่อไป
มินาโตะ

17

controllerฟังก์ชั่น / วัตถุหมายถึงสิ่งที่เป็นนามธรรมแบบ View-Controller (MVC) ในขณะที่ไม่มีอะไรใหม่ที่จะเขียนเกี่ยวกับ MVC มันยังคงเป็นความได้เปรียบที่สำคัญที่สุดของเชิงมุม: แยกข้อกังวลออกเป็นชิ้นเล็ก ๆ และนั่นคือไม่มีอะไรเพิ่มเติมดังนั้นหากคุณต้องการที่จะตอบสนองต่อModelการเปลี่ยนแปลงที่มาจากViewที่Controllerเป็นบุคคลที่เหมาะสมในการทำงาน

เรื่องราวเกี่ยวกับlinkฟังก์ชั่นนั้นแตกต่างกันมันมาจากมุมมองที่ต่างจากนั้นคือ MVC และเป็นสิ่งจำเป็นจริงๆเมื่อเราต้องการที่จะข้ามเขตแดนของ(แม่แบบ)controller/model/view

เรามาเริ่มด้วยพารามิเตอร์ที่ส่งผ่านเข้าไปในlinkฟังก์ชั่น:

function link(scope, element, attrs) {
  • scopeเป็นวัตถุขอบเขต Angular
  • องค์ประกอบเป็นองค์ประกอบห่อ jqLite ที่ตรงกับคำสั่งนี้
  • attrsเป็นวัตถุที่มีชื่อแอตทริบิวต์ปกติและค่าที่เกี่ยวข้อง

ใส่linkลงในบริบทที่เราควรจะพูดถึงว่าคำสั่งทั้งหมดจะผ่านขั้นตอนนี้กระบวนการเริ่มต้น: คอมไพล์ , การเชื่อมโยง สารสกัดจากBrad Green และ Shyam Seshadri book Angular JS :

Compile phase (น้องสาวของลิงค์เรามาพูดถึงที่นี่เพื่อรับภาพที่ชัดเจน):

ในขั้นตอนนี้ Angular จะเดิน DOM เพื่อระบุคำสั่งที่ลงทะเบียนทั้งหมดในเทมเพลต สำหรับแต่ละคำสั่งจากนั้นจะแปลง DOM ตามกฎของคำสั่ง (แม่แบบแทนที่ transclude และอื่น ๆ ) และเรียกใช้ฟังก์ชันการคอมไพล์หากมีอยู่ ผลลัพธ์ที่ได้คือฟังก์ชั่นเทมเพลตที่รวบรวม

ลิงค์เฟส :

ในการทำให้มุมมองเป็นแบบไดนามิก Angular จะเรียกใช้ฟังก์ชันลิงก์สำหรับแต่ละคำสั่ง ฟังก์ชั่นการเชื่อมโยงมักจะสร้างฟังบน DOM หรือรูปแบบ ผู้ฟังเหล่านี้คอยดูและโมเดลอยู่ตลอดเวลา

เป็นตัวอย่างที่ดีวิธีการใช้linkอาจจะพบได้ที่นี่: การสร้างแนวทางที่กำหนดเอง ดูตัวอย่าง: การสร้างคำสั่งที่จัดการกับ DOMซึ่งแทรก "วันที่ - เวลา" ในหน้ารีเฟรชทุกวินาที

เพียงตัวอย่างสั้น ๆ จากแหล่งที่อุดมไปด้วยข้างต้นแสดงการจัดการที่แท้จริงด้วย DOM มีฟังก์ชั่น hooked เพื่อ $ timeout service และยังถูกล้างในการโทรdestructorเพื่อหลีกเลี่ยงการรั่วไหลของหน่วยความจำ

.directive('myCurrentTime', function($timeout, dateFilter) {

 function link(scope, element, attrs) {

 ...

 // the not MVC job must be done
 function updateTime() {
   element.text(dateFilter(new Date(), format)); // here we are manipulating the DOM
 }

 function scheduleUpdate() {
   // save the timeoutId for canceling
   timeoutId = $timeout(function() {
     updateTime(); // update DOM
     scheduleUpdate(); // schedule the next update
   }, 1000);
 }

 element.on('$destroy', function() {
   $timeout.cancel(timeoutId);
 });

 ...

3
คุณดูเหมือนจะมีการเปรียบเทียบและcompiler linkพวกเขาถามคำถามว่าทำไมlinkเมื่อเรามีcontroller
Yugal Jindle

ฉันได้ขยายคำตอบเพื่ออธิบายแม้กระทั่งตัวควบคุมในรายละเอียดเพิ่มเติม ตอนนี้แนวคิดของcontrollerVS linkควรมีความชัดเจนมากขึ้น ...
Radim Köhler

1
ฉันสามารถหาคำอธิบายได้ แต่ดูเหมือนว่าจะพร่ามัวที่นั่น มันจะดีถ้ามีคนจากทีมงานเชิงมุมตัวเองสามารถพูดให้มันฉายที่พวกเขาเห็นมันจะ - ไปหรือlink controller
Yugal Jindle

1
นั่นเป็นเพียงส่วนเดียวที่ฉันต้องการเข้าใจ (เมื่อไม่เพียงพอ?) นอกจากนี้ฉันได้รับประโยชน์ทั้งหมดจากเชิงมุมcontrollerและlinkค่อนข้างน่าเกลียด ดังนั้นทีมงานเชิงมุมต้องมีเหตุผลที่ดีสำหรับมันแทนที่จะเป็นแค่ตัวเลือก
Yugal Jindle

1
คำถาม: เมื่อคอนโทรลเลอร์ไม่เพียงพอ ตอบ: เมื่อคุณต้องการประสบการณ์การใช้งานเชิงมุมเช่นใช้ปลั๊กอิน JQuery หรือใช้คุณสมบัติ JQlite ตามที่กล่าวไว้ในเอกสาร ( docs.angularjs.org/api/ng/function/angular.element:)คุณจำเป็นต้องมี ลิงก์
Hasteq
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.