首页 web前端 js教程 AngularJs之Scope作用域

AngularJs之Scope作用域

Nov 01, 2016 pm 03:47 PM
angular

什么是scope

  AngularJS 中,作用域是一个指向应用模型的对象,它是表达式的执行环境。作用域有层次结构,这个层次和相应的 DOM 几乎是一样的。作用域能监控表达式和传递事件。

  在 HTML 代码中,一旦一个 ng-app 指令被定义,那么一个作用域就产生了,由 ng-app 所生成的作用域比较特殊,它是一个根作用域($rootScope),它是其他所有$Scope 的最顶层。

  除了用 ng-app 指令可以产生一个作用域之外,其他的指令如 ng-controller,ng-repeat 等都会产生一个或者多个作用域。此外,还可以通过 AngularJS 提供的创建作用域的工厂方法来创建一个作用域。这些作用域都拥有自己的继承上下文,并且根作用域都为$rootScope。

  在生成一个作用域之后,在编写 AngularJS 代码时,$scope 对象就代表了这个作用域的数据实体,我们可以在$scope 内定义各种数据类型,之后可以直接在 HTML 中以 {{变量名}} 方式来让 HTML 访问到这个变量。

继承作用域

  AngularJS 在创建一个作用域时,会检索上下文,如果上下文中已经存在一个作用域,那么这个新创建的作用域就会以 JavaScript 原型继承机制继承其父作用域的属性和方法。

  一些 AngularJS 指令会创建新的子作用域,并且进行原型继承: ng-repeat、ng-include、ng-switch、ng-view、ng-controller, 用 scope: true 和 transclude: true 创建的 directive。

  以下 HTML 中定义了三个作用域,分别是由 ng-app 指令所创建的$rootScope,parentCtrl 和 childCtrl 所创建的子作用域,这其中 childCtrl 生成的作用域又是 parentCtrl 的子作用域。

示例一:作用域的继承实例

<!doctype html>
<html>
<head>
    <meta charset=utf-8"/>
    <title>scope nick</title>
    <script src="http://apps.bdimg.com/libs/angular.js/1.4.6/angular.min.js"></script>
</head>
<script type="text/javascript">
    angular.module(&#39;app&#39;, [])
            .controller(&#39;parentCtrl&#39;, [&#39;$scope&#39;, function($scope) {
                $scope.args= &#39;Nick DeveloperWorks&#39;;
            }])
            .controller(&#39;childCtrl&#39;, [&#39;$scope&#39;, function($scope) {
                $scope.args= &#39;Nick DeveloperWorks for test&#39;;
            }]);
</script>
<body ng-app="app">
<div ng-controller="parentCtrl">
    <input ng-model="args">
    <div ng-controller="childCtrl">
        <input ng-model="args">
    </div>
</div>
</body>
</html>
登录后复制

  继承作用域符合 JavaScript 的原型继承机制,这意味着如果我们在子作用域中访问一个父作用域中定义的属性,JavaScript 首先在子作用域中寻找该属性,没找到再从原型链上的父作用域中寻找,如果还没找到会再往上一级原型链的父作用域寻找。在 AngularJS 中,作用域原型链的顶端是$rootScope,AnguarJS 将会寻找到$rootScope 为止,如果还是找不到,则会返回 undefined。

  我们用实例代码说明下这个机制。首先,我们探讨下对于原型数据类型的作用域继承机制:

示例二:作用域继承实例-原始类型数据继承

<!doctype html>
<html>
<head>
    <meta charset=utf-8"/>
    <title>scope nick</title>
    <script src="http://apps.bdimg.com/libs/angular.js/1.4.6/angular.min.js"></script>
</head>
<script type="text/javascript">
    angular.module(&#39;app&#39;, [])
            .controller(&#39;parentCtrl&#39;, [&#39;$scope&#39;, function($scope) {
                $scope.args = &#39;Nick DeveloperWorks&#39;;
            }])
            .controller(&#39;childCtrl&#39;, [&#39;$scope&#39;, function($scope) {
            }]);
</script>
<body ng-app="app">
<div ng-controller="parentCtrl">
    <input ng-model="args">
    <div ng-controller="childCtrl">
        <input ng-model="args">
    </div>
</div>
</body>
</html>
登录后复制

测试运行结果:

第一个输入框:

  虽然在 childCtrl 中没有定义具体的 args 属性,但是因为 childCtrl 的作用域继承自 parentCtrl 的作用域,因此,AngularJS 会找到父作用域中的 args 属性并设置到输入框中。而且,如果我们在第一个输入框中改变内容,内容将会同步的反应到第二个输入框。

第二个输入框:

  第二个输入框的内容从此将不再和第一个输入框的内容保持同步。在改变第二个输入框的内容时,因为 HTML 代码中 model 明确绑定在 childCtrl 的作用域中,因此 AngularJS 会为 childCtrl 生成一个 args 原始类型属性。这样,根据 AngularJS 作用域继承原型机制,childCtrl 在自己的作用域找得到 args 这个属性,从而也不再会去寻找 parentCtrl 的 args 属性。从此,两个输入框的内容所绑定的属性已经是两份不同的实例,因此不会再保持同步。

现将代码做如下修改,结合以上两个场景,会出现怎样的结果?

示例三:作用域继承实例-对象数据继承

<!doctype html>
<html>
<head>
    <meta charset=utf-8"/>
    <title>scope nick</title>
    <script src="http://apps.bdimg.com/libs/angular.js/1.4.6/angular.min.js"></script>
</head>
<script type="text/javascript">
    angular.module(&#39;app&#39;, [])
            .controller(&#39;parentCtrl&#39;, [&#39;$scope&#39;, function($scope) {
                $scope.args = {};
                $scope.args.content = &#39;Nick DeveloperWorks&#39;;
            }])
            .controller(&#39;childCtrl&#39;, [&#39;$scope&#39;, function($scope) {
            }]);
</script>
<body ng-app="app">
<div ng-controller="parentCtrl">
    <input ng-model="args.content">
    <div ng-controller="childCtrl">
        <input ng-model="args.content">
    </div>
</div>
</body>
</html>
登录后复制

测试结果是无论改变任何一个输入框的内容,两者的内容始终同步。

  根据 AngularJS 的原型继承机制,如果 ng-model 绑定的是一个对象数据,那么 AngularJS 将不会为 childCtrl 创建一个 args 的对象,自然也不会有 args.content 属性。这样,childCtrl 作用域中将始终不会存在 args.content 属性,只能从父作用域中寻找,也即是两个输入框的的变化其实只是在改变 parentCtrl 作用域中的 args.content 属性。因此,两者的内容始终保持同步。

  我们再看一个例子,分析结果如何。

示例四:作用域继承实例-不再访问父作用域的数据对象。

<!doctype html>
<html>
<head>
    <meta charset=utf-8"/>
    <title>scope nick</title>
    <script src="http://apps.bdimg.com/libs/angular.js/1.4.6/angular.min.js"></script>
</head>
<script type="text/javascript">
    angular.module(&#39;app&#39;, [])
            .controller(&#39;parentCtrl&#39;, [&#39;$scope&#39;, function($scope) {
                $scope.args = {};
                $scope.args.content = &#39;Nick DeveloperWorks&#39;;
            }])
            .controller(&#39;childCtrl&#39;, [&#39;$scope&#39;, function($scope) {
                $scope.args = {};
                $scope.args.content = &#39;Nick DeveloperWorks for test&#39;;
            }]);
</script>
<body ng-app="app">
<div ng-controller="parentCtrl">
    <input ng-model="args.content">
    <div ng-controller="childCtrl">
        <input ng-model="args.content">
    </div>
</div>
</body>
</html>
登录后复制

 测试结果是两个输入框的内容永远不会同步。子作用域有实例数据对象,则不访问父作用域。

独立作用域

  独立作用域是 AngularJS 中一个非常特殊的作用域,它只在 directive 中出现。在对 directive 的定义中,我们添加上一个 scope:{} 属性,就为这个 directive 创建出了一个隔离作用域。

示例5: directive 创建出一个孤立作用域

angular.module(&#39;isolate&#39;, []).directive("isolate", function () { return {
 scope : {},
 };
})
登录后复制

  独立作用域最大的特点是不会原型继承其父作用域,对外界的父作用域保持相对的独立。因此,如果在定义了孤立作用域的 AngularJS directive 中想要访问其父作用域的属性,则得到的值为 undefined。代码如下:

示例六:独立作用域的隔离性

<!doctype html>
<html>
<head>
    <meta charset=utf-8"/>
    <title>scope nick</title>
    <script src="http://apps.bdimg.com/libs/angular.js/1.4.6/angular.min.js"></script>
</head>
<script type="text/javascript">
    angular.module(&#39;app&#39;, [])
            .controller(&#39;ctrl&#39;, [&#39;$scope&#39;, function($scope) {
                $scope.args = {};
            }])
            .directive("isolateDirective", function () {
                return {
                    scope : {},
                    link : function($scope, $element, $attr) {
                        console.log($scope.$args); //输出 undefined
                    }
                };
            });
</script>
<body ng-app="app">
<div ng-controller="ctrl">
    <div isolate-directive></div>
</div>
</body>
</html>
登录后复制

  上面的代码中通过在 directive 中声明了 scope 属性从而创建了一个作用域,其父作用域为 ctrl 所属的作用域。但是,这个作用域是孤立的,因此,它访问不到父作用域的中的任何属性。存在这样设计机制的好处是:能够创建出一些列可复用的 directive,这些 directive 不会相互在拥有的属性值上产生串扰,也不会产生任何副作用。

AngularJS 独立作用域的数据绑定

  在继承作用域中,我们可以选择子作用域直接操作父作用域数据来实现父子作用域的通信,而在独立作用域中,子作用域不能直接访问和修改父作用域的属性和值。为了能够使孤立作用域也能和外界通信,AngularJS 提供了三种方式用来打破独立作用域“孤立”这一限制。

单向绑定(@ 或者 @attr)

  这是 AngularJS 独立作用域与外界父作用域进行数据通信中最简单的一种,绑定的对象只能是父作用域中的字符串值,并且为单向只读引用,无法对父作用域中的字符串值进行修改,此外,这个字符串还必须在父作用域的 HTML 节点中以 attr(属性)的方式声明。

  使用这种绑定方式时,需要在 directive 的 scope 属性中明确指定引用父作用域中的 HTML 字符串属性,否则会抛异常。示例代码如下:

实例七: 单向绑定示例

<!doctype html>
<html>
<head>
    <meta charset=utf-8"/>
    <title>scope nick</title>
    <script src="http://apps.bdimg.com/libs/angular.js/1.4.6/angular.min.js"></script>
</head>
<script>
    angular.module(&#39;isolateScope&#39;, [])
            .directive("isolateDirective", function () {
                return {
                    replace : true,
                    template: &#39;<button>{{isolates}}</button>&#39;,
                    scope : {
                        isolates : &#39;@&#39;,
                    },
                    link : function($scope, $element, $attr) {
                        $scope.isolates = "DeveloperWorks";//无效
                    }
                };
            })
            .controller("ctrl", function ($scope) {
                $scope.btns = &#39;NICK&#39;;
            });
</script>
<body ng-app="isolateScope" >
<div ng-controller="ctrl">
    <button>{{btns}}</button>
    <div isolate-directive isolates="{{btns}}"></div>
</div>
</body>
</html>
登录后复制

  上面的代码,通过在 directive 中声明了 scope:{isolates:'@'} 使得 directive 拥有了父作用域中 data-isolates (isolates为自定义属性,不加data也可以,但建议加上data)这个 HTML 属性所拥有的值,这个值在控制器 ctrl 中被赋值为'nick'。所以,代码的运行结果是页面上有两个名为 nick的按钮。

  我们还注意到 link 函数中对 isolates 进行了修改,但是最终不会在运行结果中体现。这是因为 isolates 始终绑定为父作用域中的 btns 字符串,如果父作用域中的 btns 不改变,那么在孤立作用域中无论怎么修改 isolates 都不会起作用。

引用绑定(&或者&attr)

  通过这种形式的绑定,孤立作用域将有能力访问到父作用域中的函数对象,从而能够执行父作用域中的函数来获取某些结果。这种方式的绑定跟单向绑定一样,只能以只读的方式访问父作用函数,并且这个函数的定义必须写在父作用域 HTML 中的 attr(属性)节点上。

  这种方式的绑定虽然无法修改父作用域的 attr 所设定的函数对象,但是却可以通过执行函数来改变父作用域中某些属性的值,来达到一些预期的效果。示例代码如下:

示例八:引用绑定示例

<!doctype html>
<html>
<head>
    <meta charset=utf-8"/>
    <title>scope nick</title>
    <script src="http://apps.bdimg.com/libs/angular.js/1.4.6/angular.min.js"></script>
</head>
<script>
    angular.module(&#39;isolateScope&#39;, [])
            .directive("isolateDirective", function () {
                return {
                    replace : true,
                    scope : {
                        isolates : &#39;&&#39;,
                    },
                    link : function($scope, $element, $attr) {
                        var func = $scope.isolates();
                        func();
                    }
                };
            })
            .controller("ctrl", function ($scope) {
                $scope.func = function () {
                    console.log("Nick DeveloperWorks");
                }
            });
</script>
<body ng-app="isolateScope" >
<div ng-controller="ctrl">
    <div isolate-directive data-isolates="func"></div>
</div>
</body>
</html>
登录后复制

  这个例子中,浏览器的控制台将会打印“Nick DeveloperWorks”文字。

  上面的代码中我们在父作用域中指定了一个函数对象$scope.func,在孤立作用域中通过对 HTML 属性的绑定从而引用了 func。需要注意的是 link 函数中对 func 对象的使用方法,$scope.isolates 获得的仅仅是函数对象,而不是调用这个对象,因此我们需要在调用完$scope.isolates 之后再调用这个函数,才能得到真正的执行结果。

双向绑定(=或者=attr)

双向绑定赋予 AngularJS 孤立作用域与外界最为自由的双向数据通信功能。在双向绑定模式下,孤立作用域能够直接读写父作用域中的属性和数据。和以上两种孤立作用域定义数据绑定一样,双向绑定也必须在父作用域的 HTML 中设定属性节点来绑定。

双向绑定非常适用于一些子 directive 需要频繁和父作用域进行数据交互,并且数据比较复杂的场景。不过,由于可以自由的读写父作用域中的属性和对象,所以在一些多个 directive 共享父作用域数据的场景下需要小心使用,很容易引起数据上的混乱。

示例代码如下:

示例九:双向绑定示例

<!doctype html>
<html>
<head>
    <meta charset=utf-8"/>
    <title>scope nick</title>
    <script src="http://apps.bdimg.com/libs/angular.js/1.4.6/angular.min.js"></script>
</head>
<script>
    angular.module(&#39;isolateScope&#39;, [])
            .directive("isolateDirective", function () {
                return {
                    replace : true,
                    template: &#39;<button>{{isolates}}</button>&#39;,
                    scope : {
                        isolates : &#39;=&#39;,
                    },
                    link : function($scope, $element, $attr) {
                        $scope.isolates.name = "NICK";
                    }
                };
            })
            .controller("ctrl", function ($scope) {
                $scope.btns = {
                    name : &#39;nick&#39;,
                    dw : &#39;DeveloperWorks&#39;
                };
            });
</script>
<body ng-app="isolateScope" >
<div ng-controller="ctrl">
    <button>{{btns.dw}}</button>
    <button>{{btns.name}}</button>
    <div isolate-directive data-isolates="btns"></div>
</div>
</body>
</html>
登录后复制

 上面的代码运行的结果是浏览器页面上出现三个按钮,其中第一个按钮标题为“DeveloperWorks”,第二和第三个按钮的标题为“NICK”。

初始时父作用域中的$scope.btns.name为小写的“nick”,通过双向绑定,孤立作用域中将父作用域的 name改写成为大写的“NICK”并且直接生效,父作用域的值被更改。


本站声明
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn

热AI工具

Undresser.AI Undress

Undresser.AI Undress

人工智能驱动的应用程序,用于创建逼真的裸体照片

AI Clothes Remover

AI Clothes Remover

用于从照片中去除衣服的在线人工智能工具。

Undress AI Tool

Undress AI Tool

免费脱衣服图片

Clothoff.io

Clothoff.io

AI脱衣机

AI Hentai Generator

AI Hentai Generator

免费生成ai无尽的。

热门文章

R.E.P.O.能量晶体解释及其做什么(黄色晶体)
3 周前 By 尊渡假赌尊渡假赌尊渡假赌
R.E.P.O.最佳图形设置
3 周前 By 尊渡假赌尊渡假赌尊渡假赌
R.E.P.O.如果您听不到任何人,如何修复音频
3 周前 By 尊渡假赌尊渡假赌尊渡假赌
WWE 2K25:如何解锁Myrise中的所有内容
3 周前 By 尊渡假赌尊渡假赌尊渡假赌

热工具

记事本++7.3.1

记事本++7.3.1

好用且免费的代码编辑器

SublimeText3汉化版

SublimeText3汉化版

中文版,非常好用

禅工作室 13.0.1

禅工作室 13.0.1

功能强大的PHP集成开发环境

Dreamweaver CS6

Dreamweaver CS6

视觉化网页开发工具

SublimeText3 Mac版

SublimeText3 Mac版

神级代码编辑软件(SublimeText3)

聊聊Angular中的元数据(Metadata)和装饰器(Decorator) 聊聊Angular中的元数据(Metadata)和装饰器(Decorator) Feb 28, 2022 am 11:10 AM

本篇文章继续Angular的学习,带大家了解一下Angular中的元数据和装饰器,简单了解一下他们的用法,希望对大家有所帮助!

如何在Ubuntu 24.04上安装Angular 如何在Ubuntu 24.04上安装Angular Mar 23, 2024 pm 12:20 PM

Angular.js是一种可自由访问的JavaScript平台,用于创建动态应用程序。它允许您通过扩展HTML的语法作为模板语言,以快速、清晰地表示应用程序的各个方面。Angular.js提供了一系列工具,可帮助您编写、更新和测试代码。此外,它还提供了许多功能,如路由和表单管理。本指南将讨论在Ubuntu24上安装Angular的方法。首先,您需要安装Node.js。Node.js是一个基于ChromeV8引擎的JavaScript运行环境,可让您在服务器端运行JavaScript代码。要在Ub

angular学习之详解状态管理器NgRx angular学习之详解状态管理器NgRx May 25, 2022 am 11:01 AM

本篇文章带大家深入了解一下angular的状态管理器NgRx,介绍一下NgRx的使用方法,希望对大家有所帮助!

浅析angular中怎么使用monaco-editor 浅析angular中怎么使用monaco-editor Oct 17, 2022 pm 08:04 PM

angular中怎么使用monaco-editor?下面本篇文章记录下最近的一次业务中用到的 monaco-editor 在 angular 中的使用,希望对大家有所帮助!

一文探究Angular中的服务端渲染(SSR) 一文探究Angular中的服务端渲染(SSR) Dec 27, 2022 pm 07:24 PM

你知道 Angular Universal 吗?可以帮助网站提供更好的 SEO 支持哦!

Angular + NG-ZORRO快速开发一个后台系统 Angular + NG-ZORRO快速开发一个后台系统 Apr 21, 2022 am 10:45 AM

本篇文章给大家分享一个Angular实战,了解一下angualr 结合 ng-zorro 如何快速开发一个后台系统,希望对大家有所帮助!

如何使用PHP和Angular进行前端开发 如何使用PHP和Angular进行前端开发 May 11, 2023 pm 04:04 PM

随着互联网的飞速发展,前端开发技术也在不断改进和迭代。PHP和Angular是两种广泛应用于前端开发的技术。PHP是一种服务器端脚本语言,可以处理表单、生成动态页面和管理访问权限等任务。而Angular是一种JavaScript的框架,可以用于开发单页面应用和构建组件化的Web应用程序。本篇文章将介绍如何使用PHP和Angular进行前端开发,以及如何将它们

项目过大怎么办?如何合理拆分Angular项目? 项目过大怎么办?如何合理拆分Angular项目? Jul 26, 2022 pm 07:18 PM

Angular项目过大,怎么合理拆分它?下面本篇文章给大家介绍一下合理拆分Angular项目的方法,希望对大家有所帮助!

See all articles