2014-04-12 16 views
21

Tôi có một chỉ thị Góc đặt chiều cao của phần tử bằng với chiều cao bên trong của cửa sổ trình duyệt (+/- một độ lệch đã cho). Chỉ thị này phản hồi sự kiện "thay đổi kích thước" của cửa sổ và điều chỉnh chiều cao của cửa sổ tương ứng. Khi phạm vi của chỉ thị của tôi phát ra sự kiện '$ destory', tôi loại bỏ ràng buộc với sự kiện "thay đổi kích cỡ" (tôi nghĩ việc rời khỏi nó sẽ gây ra một số vấn đề, sửa tôi nếu tôi sai).Làm thế nào để dọn dẹp an toàn ràng buộc sự kiện AngularJS theo chỉ thị

Tôi không biết cách tách rời sự kiện này theo cách "an toàn". Điều gì xảy ra nếu tôi có nhiều phiên bản của chỉ thị này trong toàn bộ ứng dụng của mình và điều gì sẽ xảy ra nếu tôi có các chỉ thị khác đính kèm sự kiện 'thay đổi kích thước'?

JQuery có khái niệm về không gian tên sự kiện có vẻ như là một giải pháp tốt, nhưng thực hiện của Angular (JQLite) does not support this. Tôi không muốn sử dụng JQuery vì tôi đã sử dụng Angular, vì vậy tôi phải làm gì?

Dưới đây là các mã cho chỉ thị của tôi như ngày nay

window.angular.module('arcFillClient', []) 
    .directive('arcFillClientY', ['$window', 
     function ($window) { 

      function link($scope, el, attrs) { 

       var setHeight, 
        onResize, 
        cleanUp; 

       setHeight = function (offSetY) { 
        var newHeight; 
        offSetY = offSetY || 0; 
        newHeight = Math.max($window.innerHeight + parseInt(offSetY, 10)) + 'px'; 
        el.height(newHeight); 
       }; 

       onResize = function() { 
        var offset; 
        offset = attrs.arcFillClientY || 0; 
        setHeight(offset); 
       }; 

       attrs.$observe('arcFillClientY', setHeight); 
       window.angular.element($window).on('resize', onResize); 

       cleanUp = function() { 
        window.angular.element($window).off('resize'); 
       }; 

       $scope.$on('$destroy', cleanUp); 
      } 
      return { 
       link: link 
      }; 

CẬP NHẬT Trông giống như một trường hợp RTFM, nhưng chỉ trong trường hợp bất cứ ai khác đi lang thang ở đây, ở đây là một số thông tin hơn. Chuyển hàm gốc (trong trường hợp của tôi OnResize) đến .off() hoạt động để cô lập phạm vi của hàm .off(). Từ docs:

Trình xử lý cũng có thể được xóa bằng cách chỉ định tên hàm trong đối số xử lý. Khi jQuery {ahem ... JQLite} gắn một trình xử lý sự kiện, nó gán một id duy nhất cho hàm xử lý.

Dưới đây là các cập nhật cleanUp chức năng từ chỉ thị của tôi:

cleanUp = function() { 
    window.angular.element($window).off('resize', onResize); 
}; 

Cảm ơn tasseKATT, Karolis và Hans vì những đóng góp của bạn.

Trả lời

26

Vượt qua tham khảo chức năng tương tự để off như bạn vượt qua để on:

window.angular.element($window).off('resize', onResize); 

Thay vì:

window.angular.element($window).off('resize'); 

Demo - Đi qua chức năng tham chiếu đến tắt: http://plnkr.co/edit/1rfVPNXl6TrEcuYvzPAj?p=preview

Bản trình diễn - Không chuyển tham chiếu hàm thành tắt: http://plnkr.co/edit/IsLqSLAzNcHqDnhMty7Q?p=preview

Trình diễn chứa hai chỉ thị cả nghe sự kiện thay đổi kích thước cửa sổ. Sử dụng dấu tách dọc giữa mã và bản xem trước để kích hoạt sự kiện.

Bạn sẽ nhận thấy rằng nếu bạn phá hủy một thẻ còn lại sẽ tiếp tục hoạt động khi chuyển tham chiếu hàm thành tắt. Nếu không, cả hai sẽ ngừng hoạt động.

+0

Thông tin thêm về chủ đề cho những người quan tâm: http: // stackoverflow.com/a/27016855/2887841 – tasseKATT

+0

Tôi có một ý tưởng về điều này. Khi bạn áp dụng chỉ thị trên 10 phần tử, điều đó có nghĩa là cửa sổ có 10 thay đổi kích thước danh sách sự kiện với hàm onResize không? Hoặc là hàm onResize được ghi đè mỗi khi nó được đặt .... – poashoas

2

Đối với một, hoàn toàn không có gì sai khi sử dụng JQuery và AngularJS cùng nhau.

Điều đó sang một bên, những gì tôi muốn làm là có một chỉ thị body mà nghe window.on('resize', ...) và viết kích thước thành $rootScope.windowSize. Sau đó, có một chỉ thị khác trên phần tử, đến $watch("windowSize", ...) và đặt thành chiều rộng nếu cần. (Bạn không thực sự phải phơi bày kích thước trong $scope - thay vào đó bạn có thể sử dụng require).

+0

Tôi không ngụ ý rằng có bất cứ điều gì "sai" với việc sử dụng JQuery và Angular cùng nhau, chỉ là tôi muốn tránh nó ngay bây giờ. Tôi nghĩ giải pháp của bạn sẽ hoạt động, nhưng nó dựa trên ứng dụng và chỉ thị biết quá nhiều về nhau. Có một giải pháp nào giữ cho chỉ thị của tôi tự chủ hơn không? –

+0

@BillSparks, ứng dụng và chỉ thị không biết gì cả. Đó là hai chỉ thị có liên quan. Một cách tiếp cận khác có thể sử dụng một dịch vụ để đếm tham chiếu, nhưng tôi cho rằng JQuery sẽ hợp lý nhất. –

+0

xin lỗi tôi đã lạm dụng cụm từ "ứng dụng". Ý chính của những gì tôi đang nói là tôi muốn chỉ thị của tôi được đóng gói tốt để tôi có thể chia sẻ nó. Vì vậy, tôi không muốn tạo phụ thuộc bổ sung. Ngoài ra, tôi nghĩ rằng giải pháp của bạn chỉ đẩy vấn đề lên một cấp độ. Xin lỗi, nếu tôi thiếu cái gì đó. –

5

Tôi đã có câu hỏi tương tự cách đây vài tuần.

Sau khi xem qua nguồn jqLite (https://github.com/angular/angular.js/blob/master/src/jqLite.js), chúng tôi thấy phương thức on thêm sự kiện và phương pháp off xóa sự kiện qua chức năng jqLiteOff.

Nhìn sâu hơn, chúng tôi thấy jqLiteRemoveData gọi jqLiteOff. jqLiteRemoveData được gọi là jqLiteDealoc. jqLiteDealoc được gọi ở một vài nơi: jqLiteEmpty, html, replaceWithremove. jqLiteEmpty được gán cho phương thức empty của phần tử, xóa phần tử trong jQuery. html, replaceWithremove là jQuery bắt chước.

Thực hiện tìm kiếm ở nơi remove() được gọi trên một phần tử, chúng tôi thấy rằng nó được sử dụng trên hầu hết, nếu không phải là tất cả, logic thao tác DOM. Bạn có thể xem nó trong ngIf, ngSwitch, ngIncludengView. Vì vậy, tôi nghĩ rằng Angular không xử lý sự kiện lắng nghe sự kiện, miễn là bạn sử dụng jqLite để đính kèm các sự kiện và gọi remove() một cách thích hợp trong logic thao tác DOM của riêng bạn. Sử dụng jQuery để bọc một phần tử sẽ làm rối tung rất nhiều quy trình, bao gồm dọn dẹp sự kiện lắng nghe sự kiện, nhưng tôi đoán bạn đã hoàn toàn nhận thức được điều đó vì bạn đang sử dụng angular.element.

+0

Hans, đây là thông tin chi tiết có giá trị, cảm ơn bạn. Bây giờ tôi đã tự mình đào sâu vào mã nguồn và dường như, như bạn đã đề cập, các trình lắng nghe sự kiện sẽ được làm sạch bởi Angular bất cứ khi nào tôi sử dụng remove() (hoặc rõ ràng hoặc ngầm qua một chỉ thị tích hợp). Tuy nhiên, kể từ khi người nghe của tôi là trên cửa sổ $ (hoặc thay vì một phiên bản JQLite bọc của nó) nó có lẽ sẽ không bao giờ được gỡ bỏ, phải không? Điều này có nghĩa là khi phần tử của tôi bị phá hủy, tôi kết thúc với một người nghe với một trình xử lý không xác định, phải không? Xin lỗi, nếu tôi thiếu cái gì đó. –

+0

Bạn vẫn nên có một người nghe làm việc nếu nó không bị hủy đăng ký. Các đối tượng được tham chiếu thông qua việc đóng bởi người nghe cũng sẽ không bao giờ bị thu gom rác. – thynctank

Các vấn đề liên quan