$scope trong AngularJS là gì? Hướng dẫn kèm ví dụ.

⚡ Tóm tắt thông minh

`$Scope` trong AngularJS là đối tượng tích hợp sẵn dùng để liên kết bộ điều khiển với khung nhìn của nó. Trang này giải thích về việc tạo phạm vi, các hàm hành vi, hệ thống phân cấp cha con, sự khác biệt so với `$rootScope`, và cách các chu kỳ digest làm mới các liên kết.

  • 🔗 Vai trò ràng buộc: Biến `$scope` truyền các biến thành viên từ controller vào view, nhờ đó template hiển thị dữ liệu mà không cần can thiệp trực tiếp vào DOM.
  • ⚙️ Chức năng hành vi: Gắn các hàm vào biến `$scope` khi giao diện cần phản hồi các cú nhấp chuột, thay đổi dữ liệu nhập hoặc các sự kiện khác của người dùng.
  • 🌳 Thứ tự phân cấp phạm vi: Các chỉ thị như ng-controller và ng-repeat tạo ra các phạm vi con phản ánh cấu trúc cây DOM của ứng dụng.
  • 🌍 $rootScope reach: Mỗi ứng dụng chỉ có một $rootScope duy nhất và nó hoạt động như một đối tượng toàn cục mà mọi phạm vi con đều có thể đọc được.
  • 🔍 Chu trình tiêu hóa: $watch đăng ký các trình lắng nghe, $apply vào ngữ cảnh thực thi của AngularJS và $digest so sánh các giá trị cho đến khi mô hình ổn định.
  • 🚀 Thói quen hiệu suất: Hãy giữ cho các biểu thức theo dõi (watch expressions) có chi phí thấp, tránh truy cập DOM bên trong chúng và gọi `$destroy` trên các phạm vi không còn cần thiết nữa.

$Scope trong AngularJS là gì?

$scope trong AngularJS là gì?

$ phạm vi trong AngularJS là một đối tượng tích hợp về cơ bản liên kết “bộ điều khiển” và “chế độ xem”. Người ta có thể xác định các biến thành viên trong phạm vi bên trong bộ điều khiển mà sau đó khung nhìn có thể được truy cập.

Mỗi bộ điều khiển trong một AngularJS Ứng dụng nhận được một thể hiện `$scope` riêng thông qua cơ chế tiêm phụ thuộc. Bất cứ thứ gì bạn gắn vào đối tượng đó đều trở nên hiển thị cho mẫu mà bộ điều khiển quản lý, vì vậy `$scope` hoạt động như một mô hình dữ liệu được chia sẻ nằm giữa ứng dụng của bạn và các ứng dụng khác. JavaLogic kịch bản và mã HTML của bạn.

Hãy xem xét ví dụ dưới đây:

$ phạm vi trong AngularJS

angular.module('app',[]).controller('HelloWorldCtrl',
	function($scope)
	{
		$scope.message = "Hello World"
	});

Code Giải thích:

  1. Tên của mô-đun là “ứng dụng”
  2. Tên của bộ điều khiển là “HelloWorldCtrl”
  3. Đối tượng phạm vi là đối tượng chính được sử dụng để truyền thông tin từ bộ điều khiển đến khung nhìn.
  4. Biến thành viên được thêm vào đối tượng phạm vi

⚠️ Cảnh báo cú pháp: .controller() Phương thức này nhận hai đối số, tên bộ điều khiển và hàm tạo, vì vậy cần có dấu phẩy giữa chúng. 'HelloWorldCtrl'function($scope)Việc bỏ sót dấu phẩy sẽ gây ra lỗi. Uncaught SyntaxError Trước khi AngularJS được khởi tạo.

Một bộ điều khiển duy nhất và một giao diện duy nhất chỉ là một nửa bức tranh. Các ứng dụng thực tế lồng nhau các bộ điều khiển, lặp lại danh sách và tái sử dụng các widget, điều đó có nghĩa là có nhiều phạm vi tồn tại cùng một lúc.

Cách thức hoạt động của phân cấp phạm vi và kế thừa trong AngularJS

Mỗi ứng dụng AngularJS đều có chính xác một phạm vi gốc và có thể có bất kỳ số lượng phạm vi con nào. Các chỉ thị tạo ra các phạm vi con đó và gắn chúng vào phần tử DOM mà chúng trang trí, do đó cây phạm vi phản ánh cấu trúc của trang được hiển thị.

Khi AngularJS đánh giá một biểu thức như sau: {{siteName}}Đầu tiên, nó tìm kiếm thuộc tính đó trong phạm vi được gắn với phần tử. Nếu thuộc tính không có, quá trình tìm kiếm sẽ chuyển sang phạm vi cha và tiếp tục leo lên cho đến khi đạt đến phạm vi gốc. JavaCác nhà phát triển kịch bản biết hành vi này là kế thừa nguyên mẫu, và phạm vi con kế thừa từ phạm vi cha của chúng theo đúng cách đó.

Ví dụ bên dưới lồng một bộ điều khiển vào bên trong một bộ điều khiển khác để bạn có thể quan sát quá trình kế thừa.

<div ng-app="scopeDemo">
    <div ng-controller="ParentCtrl">
        Parent scope value: {{siteName}}
        <div ng-controller="ChildCtrl">
            Child reads parent value: {{siteName}}
            Child own value: {{lesson}}
        </div>
    </div>
</div>

<script type="text/javascript">
    var app = angular.module("scopeDemo", []);

    app.controller("ParentCtrl", function($scope) {
        $scope.siteName = "Guru99";
    });

    app.controller("ChildCtrl", function($scope) {
        $scope.lesson = "AngularJS Scope";
    });
</script>

Code Giải thích:

  1. ParentCtrl định nghĩa siteName trong phạm vi riêng của nó.
  2. ChildCtrl không bao giờ định nghĩa siteNameTuy nhiên, div bên trong vẫn in ra. Guru99 vì quá trình tra cứu truy cập đến phạm vi cha.
  3. lesson Nó chỉ tồn tại trong phạm vi con, vì vậy div cha không thể đọc được nó.

Những chỉ thị nào tạo ra một phạm vi mới?

  • ng-controller: Tạo một phạm vi con cho phần tử mà nó được đặt lên.
  • ng-repeat: Mỗi lần lặp tạo ra một phạm vi con duy nhất, đó là lý do tại sao mỗi hàng có thể chứa các giá trị khác nhau cho cùng một biểu thức.
  • Các chỉ thị tùy chỉnh: có thể yêu cầu kính nội soi cho trẻ em, hoặc một cô lập phạm vi này cố ý không kế thừa từ phạm vi cha của nó.
  • Chỉ thị thành phần: bất cứ thứ gì được đăng ký với .component() Người trợ giúp luôn nhận được một phạm vi cô lập.

Vì phạm vi con đọc từ dưới lên trên, các nhà phát triển thường tự hỏi đỉnh của chuỗi đó nằm ở đâu. Đối tượng cấp cao nhất đó được gọi là `$rootScope`.

$scope so với $rootScope: Sự khác biệt là gì?

AngularJS $rootScope $rootScope là phạm vi cho toàn bộ ứng dụng. Một ứng dụng chỉ có thể có một $rootScope duy nhất và nó được sử dụng như một biến toàn cục. Mỗi $scope là một phạm vi con, và $rootScope là phạm vi cha ở đỉnh của cây. Bảng dưới đây so sánh hai đối tượng này.

Yếu tố phạm vi $ $rootScope
Số lượng phiên bản cho mỗi ứng dụng Nhiều, mỗi bộ điều khiển hoặc chỉ thị tạo phạm vi có một chỉ thị. Chính xác là một
Tạo bởi Các chỉ thị như ng-controller và ng-repeat Bộ tiêm trong quá trình khởi động ứng dụng
Hình ảnh tốt Nguyên tố riêng của nó và tất cả các hậu duệ của nó Mọi phạm vi trong ứng dụng
Sử dụng điển hình Dữ liệu và hành vi cho một chế độ xem hoặc một hàng trong danh sách. Các giá trị áp dụng trên toàn ứng dụng, chẳng hạn như người dùng đã đăng nhập.
rủi ro chính Các giá trị trở nên không thể đạt được bên ngoài nhánh Xung đột tên và liên kết ngầm, giống như các biến toàn cục.

Hãy sử dụng `$rootScope` một cách tiết kiệm. Bất cứ thứ gì được đặt ở đó đều tồn tại trong toàn bộ ứng dụng và có thể đọc được ở mọi nơi, vì vậy một dịch vụ dùng chung thường là nơi an toàn hơn cho trạng thái toàn cục. (Lưu ý: Đoạn mã chính thức không liên quan đến đoạn mã trên.) Tham chiếu $rootScope Liệt kê toàn bộ API.

Biết được dữ liệu nằm ở đâu chỉ là một nửa công việc. Nửa còn lại là hướng dẫn nhóm phát triển cách phản hồi khi người dùng thực hiện thao tác nào đó.

Thiết lập hoặc thêm hành vi trong AngularJS

Để phản ứng với các sự kiện hoặc thực hiện một số loại tính toán/xử lý trong Chế độ xem, chúng tôi phải cung cấp hành vi cho phạm vi.

Các hành vi được thêm vào các đối tượng phạm vi để phản hồi các sự kiện cụ thể có thể được Chế độ xem kích hoạt. Khi hành vi được xác định trong bộ điều khiển, nó có thể được truy cập bằng chế độ xem.

Hãy xem một ví dụ về cách chúng ta có thể đạt được điều này.

Thiết lập hoặc thêm Hành vi

<!DOCTYPE html>  
<html lang="en">  
<head>  
    <meta chrset="UTF 8">
    <title>Guru99</title>     
</head>  
<body ng-app="DemoApp">
<h1> Guru99 Global Event</h1>
<script src="https://code.angularjs.org/1.6.9/angular.js"></script>
<div ng-controller="DemoController">
	{{fullName("Guru","99")}}
</div>
<script type="text/javascript">  
	var app = angular.module("DemoApp", []);
	app.controller("DemoController", function($scope) {
    
    $scope.fullName=function(firstName,lastname){
		return firstName + lastname;
		}
	} );
</script> 

</body>  
</html>

Code Giải thích:

  1. Chúng tôi đang tạo một hành vi có tên là “fullName”. Hành vi này là một hàm chấp nhận 2 tham số (firstName,lastname).
  2. Hành vi sau đó trả về kết nối của 2 tham số này.
  3. Trong quan điểm này, chúng ta đang gọi hành vi và truyền vào 2 giá trị của “Guru“ và “99” được truyền làm tham số cho hành vi.

Nếu lệnh được thực thi thành công, kết quả sau sẽ hiển thị khi bạn chạy mã trên trình duyệt.

Đầu ra:

Thiết lập hoặc thêm Hành vi

Trong trình duyệt, bạn sẽ thấy sự kết hợp của cả hai giá trị. Guru & 99 được truyền sang hành vi trong điều khiển.

Các liên kết như trên tự động được làm mới, và việc hiểu rõ cơ chế hoạt động của chúng rất quan trọng trước khi ứng dụng phát triển lớn mạnh.

Tại sao Scope Watchers và chu kỳ tóm tắt lại quan trọng?

AngularJS duy trì sự đồng bộ giữa giao diện người dùng và phạm vi bằng cách kiểm tra thay đổi (dirty checking) thay vì thông qua các sự kiện thay đổi (change events). Ba API phạm vi điều khiển quá trình này:

  • $watch: Đăng ký trình lắng nghe cho một biểu thức. Các phép nội suy như {{fullName}} Đăng ký người theo dõi cho bạn trong quá trình liên kết mẫu.
  • $apply: Nó đi vào ngữ cảnh thực thi của AngularJS, đánh giá mã của bạn và sau đó kích hoạt một hàm xử lý. Nó chỉ cần thiết bên trong các hàm gọi lại sự kiện tùy chỉnh hoặc hàm gọi lại thư viện bên thứ ba, vì các chỉ thị tích hợp sẵn đã gọi nó rồi.
  • $digest: Duyệt qua từng watcher trên $rootScope và các watcher con của nó, so sánh giá trị hiện tại với giá trị trước đó, và lặp lại cho đến khi mô hình ngừng thay đổi.

Vì quá trình xử lý digest có thể chạy nhiều lần, nên các biểu thức theo dõi (watch expressions) phải có chi phí thấp. Tránh truy cập DOM bên trong chúng, vì việc đọc DOM chậm hơn nhiều lần so với việc đọc một đối tượng khác. JavaThuộc tính kịch bản.

Độ sâu của đồng hồ cũng ảnh hưởng đến chi phí. Đồng hồ theo giá trị tham chiếu là phương pháp nhanh nhất và chỉ phát hiện khi toàn bộ giá trị được thay thế. $watchCollection Thông báo các mục được thêm, xóa hoặc sắp xếp lại bên trong một mảng hoặc đối tượng. Việc theo dõi theo giá trị sẽ duyệt qua một cấu trúc lồng nhau trên mỗi bản tóm tắt và là tùy chọn tốn kém nhất, vì vậy hãy sử dụng nó sau cùng.

Câu Hỏi Thường Gặp

Một phạm vi cô lập không kế thừa nguyên mẫu từ phạm vi cha của nó. Các chỉ thị thành phần được xây dựng bằng trình trợ giúp .component() luôn nhận được một phạm vi cô lập, điều này giúp các widget có thể tái sử dụng độc lập với bộ điều khiển xung quanh và ngăn chặn việc đọc nhầm các thuộc tính của cha.

`$emit` gửi một sự kiện phạm vi lên trên thông qua các phạm vi cha hướng tới `$rootScope`, trong khi `$broadcast` gửi nó xuống dưới đến mọi phạm vi con. Cả hai đều được nhận bằng `$on`. Hãy sử dụng `$broadcast` một cách tiết kiệm, vì nó sẽ truy cập mọi phạm vi con cháu.

Hãy gọi `scope.$destroy()` khi một phạm vi con không còn cần thiết nữa. Điều này ngăn chặn việc lan truyền mã băm vào phạm vi và cho phép bộ thu gom rác lấy lại các mô hình của nó. Đồng thời, hãy hủy đăng ký các trình theo dõi thủ công bằng cách gọi hàm mà `$watch` trả về.

Các trợ lý như Trợ lý GitHub Chúng tạo ra các đoạn mã mẫu cho phạm vi một cách nhanh chóng, nhưng vẫn phát sinh các lỗi như thiếu dấu phẩy trong quá trình đăng ký bộ điều khiển. Hãy kiểm tra mọi đoạn mã được tạo ra so với mã chính thức. Tài liệu về phạm vi (scope) của AngularJS.

Các trợ lý AI ánh xạ các thuộc tính `$scope` lên các trường của lớp thành phần và viết lại logic `$watch` dưới dạng tín hiệu hoặc luồng RxJS. Hãy kết hợp chúng với thư viện chính thức. có góc cạnh cần lập tài liệu và chạy các bài kiểm tra đơn vị, vì các chuyển đổi được tạo ra thường bỏ sót các tra cứu phạm vi kế thừa.

Tóm tắt bài viết này với: