Liên kết vs biên dịch vs bộ điều khiển


529

Khi bạn tạo một lệnh, bạn có thể đặt mã vào trình biên dịch, hàm liên kết hoặc bộ điều khiển.

Trong các tài liệu, họ giải thích rằng:

  • chức năng biên dịch và liên kết được sử dụng trong các giai đoạn khác nhau của chu kỳ góc
  • bộ điều khiển được chia sẻ giữa các chỉ thị

Tuy nhiên, đối với tôi không rõ, loại mã nào nên đi đâu.

Ví dụ: Tôi có thể tạo các hàm trong biên dịch và có gắn chúng vào phạm vi trong liên kết không hoặc chỉ gắn các hàm vào phạm vi trong bộ điều khiển?

Làm thế nào các bộ điều khiển được chia sẻ giữa các chỉ thị, nếu mỗi chỉ thị có thể có bộ điều khiển riêng? Các bộ điều khiển có thực sự được chia sẻ hay nó chỉ là thuộc tính phạm vi?



Có lẽ một tổng quan toàn diện hơn về các chức năng chỉ thị: Chỉ thị góc - khi nào nên sử dụng biên dịch, bộ điều khiển, liên kết trước và sau liên kết .
Izhaki

1
Tôi đã viết một bài đăng với sơ đồ vòng đời của chỉ thị (giai đoạn tạo). Có lẽ nó giúp được ai đó: filimanjaro.com/2014/
trung bình Joe

Câu trả lời:


470

Biên dịch:

Đây là giai đoạn mà Angular thực sự biên dịch chỉ thị của bạn. Hàm biên dịch này được gọi chỉ một lần cho mỗi tham chiếu đến lệnh đã cho. Ví dụ: giả sử bạn đang sử dụng lệnh ng-repeat. ng-repeat sẽ phải tra cứu phần tử mà nó được gắn vào, trích xuất đoạn html mà nó được gắn vào và tạo một hàm mẫu.

Nếu bạn đã sử dụng HandBars, các mẫu gạch dưới hoặc tương đương, thì giống như biên dịch các mẫu của chúng để trích xuất một hàm mẫu. Đối với hàm mẫu này, bạn truyền dữ liệu và giá trị trả về của hàm đó là html với dữ liệu ở đúng nơi.

Giai đoạn biên dịch là bước trong Angular trả về hàm mẫu. Hàm mẫu này trong góc được gọi là hàm liên kết.

Giai đoạn liên kết:

Pha liên kết là nơi bạn đính kèm dữ liệu ($ scope) vào hàm liên kết và nó sẽ trả về cho bạn html được liên kết. Vì lệnh này cũng chỉ định nơi html này đi hoặc những gì nó thay đổi, nên nó đã tốt để đi. Đây là chức năng mà bạn muốn thực hiện các thay đổi đối với html được liên kết, tức là html đã có dữ liệu được đính kèm. Trong góc nếu bạn viết mã trong hàm liên kết thì nó thường là hàm post-link (theo mặc định). Nó là một kiểu gọi lại được gọi sau khi hàm liên kết đã liên kết dữ liệu với mẫu.

Điều khiển:

Bộ điều khiển là nơi bạn đặt một số logic cụ thể chỉ thị. Logic này cũng có thể đi vào chức năng liên kết, nhưng sau đó bạn sẽ phải đưa logic đó vào phạm vi để làm cho nó "có thể chia sẻ". Vấn đề với điều đó là sau đó bạn sẽ làm hỏng phạm vi với các công cụ chỉ thị của bạn không thực sự là điều được mong đợi. Vậy đâu là sự thay thế nếu hai Chỉ thị muốn nói chuyện với nhau / hợp tác với nhau? Tất nhiên, bạn có thể đặt tất cả logic đó vào một dịch vụ và sau đó thực hiện cả hai chỉ thị này phụ thuộc vào dịch vụ đó nhưng điều đó chỉ mang lại thêm một sự phụ thuộc. Cách khác là cung cấp Bộ điều khiển cho phạm vi này (thường cách ly phạm vi?) Và sau đó bộ điều khiển này được đưa vào một lệnh khác khi lệnh đó "yêu cầu" một phạm vi khác.


67
Để làm rõ: biên dịch biên dịch mẫu sẽ được sử dụng trên toàn trang. Linker được gắn với mỗi trường hợp. Đúng? Bộ điều khiển sau đó hoạt động giữa các trường hợp.
Zlatko

4
@CMCDragonkai cho mỗi controllerhàm chỉ thị được thực thi sau khi biên dịch, nhưng trước đó pre-link trong một nhánh cây DOM cục bộ. Ngoài ra controllervà các pre-linkhàm được thực thi đi ngang qua nhánh DOM cục bộ theo cách từ trên xuống . Sau đó post-linkđược thực hiện theo cách từ dưới lên .
Artem Platonov

9
Nó chỉ là một mớ hỗn độn nếu bạn không hiểu nó. Có một lý do để nó làm những gì nó làm.
demisx 24/2/2015

3
Đây là câu trả lời kỹ thuật chính xác, tuy nhiên, tôi vẫn còn những câu hỏi khi nào tôi nên sử dụng chức năng liên kết.
Nicholas Marshall

2
Chúng ta sẽ sử dụng controllerthay vì linkở khắp mọi nơi? Vì vậy, tôi không cần thay đổi mã trong tương lai nếu phương thức này cần được chia sẻ hoặc một số logic sẽ được giới thiệu?. Có bất kỳ cạm bẫy trong việc sử dụng controllertất cả các thời gian thay vì liên kết?
JPS

99

Tôi cũng muốn thêm những gì cuốn sách O'Reily AngularJS của Nhóm Google đã nói:

Bộ điều khiển - Tạo bộ điều khiển xuất bản API để liên lạc qua các chỉ thị. Một ví dụ điển hình là Chỉ thị cho Truyền thông Chỉ thị

Liên kết - Lập trình sửa đổi các phiên bản phần tử DOM kết quả, thêm trình lắng nghe sự kiện và thiết lập ràng buộc dữ liệu.

Biên dịch - Sửa đổi lập trình mẫu DOM cho các tính năng trên các bản sao của lệnh, như khi được sử dụng trong ng-repeat. Hàm biên dịch của bạn cũng có thể trả về các hàm liên kết để sửa đổi các thể hiện phần tử kết quả.


Liên kết thinkster.io của bạn không thể được xem mà không phải trả tiền. Không phải liên kết của tôi, nhưng có lẽ điều này phù hợp hơn: babmotto.com/directive-to-directive-c truyền thông
R. van Twisk

51

A directivecho phép bạn mở rộng vốn từ vựng HTML theo cách khai báo để xây dựng các thành phần web. Các ng-appthuộc tính là một chỉ thị, như vậy là ng-controllervà tất cả các ng- prefixed attributes. Chỉ thị có thể attributes, tagshoặc thậm chí class names, comments.

Làm thế nào các chỉ thị được sinh ra ( compilationinstantiation)

Biên dịch: Chúng tôi sẽ sử dụng compilehàm cho cả manipulateDOM trước khi nó được kết xuất và trả về một linkhàm (sẽ xử lý liên kết cho chúng tôi). Đây cũng là nơi để đặt bất kỳ phương pháp nào cần được chia sẻ xung quanh với tất cả các instanceschỉ thị này.

liên kết: Chúng tôi sẽ sử dụng linkchức năng để đăng ký tất cả người nghe trên một thành phần DOM cụ thể (được sao chép từ mẫu) và thiết lập các liên kết của chúng tôi với trang.

Nếu được đặt trong compile()hàm, chúng sẽ chỉ được đặt một lần (thường là những gì bạn muốn). Nếu được đặt trong link()hàm, chúng sẽ được đặt mỗi khi phần tử HTML được liên kết với dữ liệu trong đối tượng.

<div ng-repeat="i in [0,1,2]">
    <simple>
        <div>Inner content</div>
    </simple>
</div>

app.directive("simple", function(){
   return {
     restrict: "EA",
     transclude:true,
     template:"<div>{{label}}<div ng-transclude></div></div>",        
     compile: function(element, attributes){  
     return {
             pre: function(scope, element, attributes, controller, transcludeFn){

             },
             post: function(scope, element, attributes, controller, transcludeFn){

             }
         }
     },
     controller: function($scope){

     }
   };
});

CompileHàm trả về hàm prepostliên kết. Trong hàm liên kết trước, chúng ta có mẫu cá thể và phạm vi từ controller, nhưng mẫu không bị ràng buộc với phạm vi và vẫn không có nội dung được nhúng.

Postchức năng liên kết là nơi bài viết liên kết là chức năng cuối cùng để thực hiện. Bây giờ transclusionlà hoàn thành the template is linked to a scope, và view will update with data bound values after the next digest cycle. Các linktùy chọn chỉ là một phím tắt để thiết lập một post-linkchức năng.

bộ điều khiển: Bộ điều khiển chỉ thị có thể được chuyển sang giai đoạn liên kết / biên dịch lệnh khác. Nó có thể được tiêm vào các chỉ thị khác như một phương tiện để sử dụng trong giao tiếp giữa các chỉ thị.

Bạn phải chỉ định tên của lệnh được yêu cầu - Nó phải được liên kết với cùng một phần tử hoặc phần tử mẹ của nó. Tên có thể được bắt đầu bằng:

?  Will not raise any error if a mentioned directive does not exist.
^  Will look for the directive on parent elements, if not available on the same element.

Sử dụng dấu ngoặc vuông [‘directive1′, ‘directive2′, ‘directive3′]để yêu cầu nhiều bộ điều khiển chỉ thị.

var app = angular.module('app', []);

app.controller('MainCtrl', function($scope, $element) {
});

app.directive('parentDirective', function() {
  return {
    restrict: 'E',
    template: '<child-directive></child-directive>',
    controller: function($scope, $element){
      this.variable = "Hi Vinothbabu"
    }
  }
});

app.directive('childDirective', function() {
  return {
    restrict:  'E',
    template: '<h1>I am child</h1>',
    replace: true,
    require: '^parentDirective',
    link: function($scope, $element, attr, parentDirectCtrl){
      //you now have access to parentDirectCtrl.variable
    }
  }
});

1
bạn đã đề cập rằng bạn đã chỉ ra cách đưa ParentDirectiveCtrl vào bộ điều khiển của con ... ví dụ này đứa trẻ không có bộ điều khiển, mà là chức năng liên kết ... Hiện tại tôi không bị mắc kẹt về vấn đề này, vì vậy nó có thể không rất quan trọng, nhưng một câu hỏi tò mò
alockwood05

13

Ngoài ra, một lý do chính đáng để sử dụng bộ điều khiển so với chức năng liên kết (vì cả hai đều có quyền truy cập vào phạm vi, phần tử và attrs) là vì bạn có thể chuyển bất kỳ dịch vụ có sẵn hoặc phụ thuộc nào vào bộ điều khiển (và theo bất kỳ thứ tự nào), trong khi bạn không thể làm điều đó với chức năng liên kết. Lưu ý các chữ ký khác nhau:

controller: function($scope, $exceptionHandler, $attr, $element, $parse, $myOtherService, someCrazyDependency) {...

so với

link: function(scope, element, attrs) {... //no services allowed

2
Vui lòng để lại một bình luận để giải thích quan điểm của bạn khi bạn downvote một câu trả lời. Cảm ơn
svassr

53
Tôi không phải là người hạ cấp, nhưng điều này không hoàn toàn chính xác bởi vì bạn vẫn có thể đưa bất kỳ sự phụ thuộc cần thiết nào vào chính lệnh, ví dụ : module.directive('myDirective', function($window) { etc.... Điều này sau đó có thể được truy cập từ bên trong chức năng liên kết.
Mike Chamberlain

1
điều này dường như không chính xác vì bạn có thể đưa dịch vụ vào chức năng liên kết
Code Whisperer

1
@JoshRibakoff Kết quả cuối cùng là như nhau, bạn có quyền truy cập vào dịch vụ trong chức năng liên kết. Nó không quan trọng cho dù nó được khai báo trong các đối số của hàm hay không. Về vấn đề này Mike Chamberlain là chính xác
Connor Wyatt

1
@ cwyatt1 Tôi đã sửa lỗi cách nói, plnkr không hiển thị việc tiêm vào hàm link () vì đó không phải là một tính năng mà Angular có. Bạn có thể nghĩ rằng tôi là người tầm thường nhưng nhận xét về siêu dữ liệu đã vạch ra rất nhiều sự khác biệt quan trọng giữa những gì plunkr làm và việc tiêm vào bộ điều khiển. OP đang hỏi sự khác biệt là gì và có sự khác biệt.
Josh Ribakoff

10

đây là một mẫu tốt để hiểu các pha chỉ thị http://codepen.io/anon/pen/oXMdBQ?editors=101

var app = angular.module('myapp', [])

app.directive('slngStylePrelink', function() {
    return {
        scope: {
            drctvName: '@'
        },
        controller: function($scope) {
            console.log('controller for ', $scope.drctvName);
        },
        compile: function(element, attr) {
            console.log("compile for ", attr.name)
            return {
                post: function($scope, element, attr) {
                    console.log('post link for ', attr.name)
                },
                pre: function($scope, element, attr) {
                    $scope.element = element;
                    console.log('pre link for ', attr.name)
                        // from angular.js 1.4.1
                    function ngStyleWatchAction(newStyles, oldStyles) {
                        if (oldStyles && (newStyles !== oldStyles)) {
                            forEach(oldStyles, function(val, style) {
                                element.css(style, '');
                            });
                        }
                        if (newStyles) element.css(newStyles);
                    }

                    $scope.$watch(attr.slngStylePrelink, ngStyleWatchAction, true);

                    // Run immediately, because the watcher's first run is async
                    ngStyleWatchAction($scope.$eval(attr.slngStylePrelink));
                }
            };
        }
    };
});

html

<body ng-app="myapp">
    <div slng-style-prelink="{height:'500px'}" drctv-name='parent' style="border:1px solid" name="parent">
        <div slng-style-prelink="{height:'50%'}" drctv-name='child' style="border:1px solid red" name='child'>
        </div>
    </div>
</body>

4
Bạn có thể xây dựng trên lý do tại sao mẫu mã này sẽ giúp đỡ để hiểu sự khác biệt giữa link, compilecontroller?
cel sharp

Bạn có biết làm thế nào một lệnh required có thể được đưa vào bộ điều khiển của lệnh phụ thuộc không?
alockwood05

Ví dụ về codepen của bạn: Uncaught Error: [$ kim phun: modulerr] Không thể khởi tạo mô-đun myapp do: Lỗi: [$ kim phun: uns] Nhà cung cấp không xác định: slngStylePrelinkProvider
rofrol 8/11/2016

7
  • biên dịch : được sử dụng khi chúng ta cần sửa đổi mẫu lệnh, như thêm biểu thức mới, nối thêm một lệnh khác trong lệnh này
  • Trình điều khiển : được sử dụng khi chúng ta cần chia sẻ / tái sử dụng dữ liệu $ scope
  • link : nó là một hàm được sử dụng khi chúng ta cần đính kèm trình xử lý sự kiện hoặc để thao tác DOM.
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.