AngularJS子級作用域問題(ngInclude;ngView;ngSwitch;ngRepeat)

大家在使用angularjs的時候,很容易忽略AngularJS自帶指令的作用域問題,有一些指令會產生獨立的自己作用域,造成子級無法與父級作用域雙向綁定的問題。這些指令目前有<code>ng-include</code>、<code>ng-view</code>、<code>ng-switch</code>、<code>ng-repeat</code>。這樣的原因是因為,這些指令雖然是AngularJS內部定義的,但是也是和<code>directive</code>實現的方法都是一樣的,其內部使用的是<code>scope:true</code>的方式,子作用域繼承了父級的作用,并且構建了一個獨立的子作用域,所有雙向綁定實現不了,只能單獨實現子級作用域繼承父級的屬性。<p>
AngularJS的繼承是通過javascript的原型繼承方式實現的,進行原型繼承即意味著父作用域在子作用域的原型鏈上。因為原型鏈的檢索只會在屬性檢索的時候觸發,不會在改變屬性值的時候觸發。所以我們需要把原始類型轉換成對象,把值綁定在對象的屬性上。<p>


示例.gif

大家可以在示例上看到,經過改造之后,就可以實現子級修改父級作用域的屬性。原始類型只能繼承父類的作用域。實現方法目前看有三種,下面一次來介紹<p>

通過給父級scope上添加<code>{}</code>來實現,把原始類型轉換成對象。代碼如下:

<!DOCTYPE html>
<html lang="en" ng-app="childScope">
<head>
    <meta charset="UTF-8">
    <title></title>
    <script src="lib/angular.min.js" type="text/javascript"></script>
    <style>
        .inputOne{
            width: 100px;
            height: 50px;
            background: skyblue;
        }
        .inner{
            border: 1px solid skyblue;
            width: 200px;
            height: 150px;
        }
        .outer{
            border: 1px solid salmon;
            width: 200px;
            height: 150px;
        }
        .sco{
            background: skyblue;
        }
    </style>
</head>
<body ng-controller="childCon">
    <div class="inner">
        <h3>父級作用域</h3>
        <span>{{vm.private1}}</span>
        <span>{{vm.private2}}</span>
    </div>
    <div class="outer">
        <h3>自己作用域</h3>
        <div class="one" ng-include src="'one.html'"></div>
        <div class="two" ng-include src="'two.html'"></div>
    </div>
</body>
<script>
    var app=angular.module("childScope",['template'])
                .controller("childCon",["$scope", function ($scope) {
                var vm=$scope.vm={};
                vm.private1=12;
                vm.private2=13;
                $scope.test=123;
            }]);
    var template=angular.module("template",[])
            .run(["$templateCache", function ($templateCache) {
                $templateCache.put("one.html","" +
                        "<div><input type='text' ng-model='vm.private1'/></div>")
            }])
            .run(["$templateCache", function ($templateCache) {
                $templateCache.put("two.html","" +
                        "<div><input type='text' ng-model='vm.private2'/>" +
                        "<div class='sco'><span>原始類型</span>{{test}}</div>" +
                        "</div>")
            }])
</script>
</html>

通過<code>controller as</code>語法來實現

<code>controller as</code>其實相當于controller的示例對象,原理還是把原始類型轉換成對象類型。

<!DOCTYPE html>
<html lang="en" ng-app="childScope">
<head>
    <meta charset="UTF-8">
    <title></title>
    <script src="lib/angular.min.js" type="text/javascript"></script>
    <style>
        .inputOne{
            width: 100px;
            height: 50px;
            background: skyblue;
        }
        .inner{
            border: 1px solid skyblue;
            width: 200px;
            height: 150px;
        }
        .outer{
            border: 1px solid salmon;
            width: 200px;
            height: 150px;
        }
        .sco{
            background: skyblue;
        }
    </style>
</head>
<body ng-controller="childCon as vm">
    <div class="inner">
        <h3>父級作用域</h3>
        <span>{{vm.private1}}</span>
        <span>{{vm.private2}}</span>
    </div>
    <div class="outer">
        <h3>自己作用域</h3>
        <div class="one" ng-include src="'one.html'"></div>
        <div class="two" ng-include src="'two.html'"></div>
    </div>
</body>
<script>
    var app=angular.module("childScope",['template'])
            .controller("childCon",["$scope", function ($scope) {
                this.private1=12;
                this.private2=22;
                $scope.test=123;
            }]);
    var template=angular.module("template",[])
            .run(["$templateCache", function ($templateCache) {
                $templateCache.put("one.html","" +
                        "<div><input type='text' ng-model='vm.private1'/></div>")
            }])
            .run(["$templateCache", function ($templateCache) {
                $templateCache.put("two.html","" +
                        "<div><input type='text' ng-model='vm.private2'/>" +
                        "<div class='sco'><span>原始類型</span>{{test}}</div>" +
                        "</div>")
            }])
</script>
</html>

使用<code>$parent.name</code>調用內部方法來實現。

進行原型繼承即意味著父作用域在子作用域的原型鏈上,這是JavaScript的特性。AngularJS的作用域還存在如下內部定義的關系:
<ul>
<li>scope.$parent指向scope的父作用域;</li>
<li>scope.$$childHead指向scope的第一個子作用域;</li>
<li>scope.$$childTail指向scope的最后一個子作用域;</li>
<li>scope.$$nextSibling指向scope的下一個相鄰作用域;</li>
<li>scope.$$prevSibling指向scope的上一個相鄰作用域;</li>
</ul>
通過在子級作用域中使用<code>scope.$parent.name</code>,來獲取對父級作用域的雙向綁定。
示例如下:

<!DOCTYPE html>
<html lang="en" ng-app="childScope">
<head>
    <meta charset="UTF-8">
    <title></title>
    <script src="lib/angular.min.js" type="text/javascript"></script>
    <style>
        .inputOne{
            width: 100px;
            height: 50px;
            background: skyblue;
        }
        .inner{
            border: 1px solid skyblue;
            width: 200px;
            height: 150px;
        }
        .outer{
            border: 1px solid salmon;
            width: 200px;
            height: 150px;
        }
        .sco{
            background: skyblue;
        }
    </style>
</head>
<body ng-controller="childCon">
    <div class="inner">
        <h3>父級作用域</h3>
        <span>{{private1}}</span>
        <span>{{private2}}</span>
    </div>
    <div class="outer">
        <h3>自己作用域</h3>
        <div class="one" ng-include src="'one.html'"></div>
        <div class="two" ng-include src="'two.html'"></div>
    </div>
</body>
<script>
    var app=angular.module("childScope",['template'])
            .controller("childCon",["$scope", function ($scope) {
                $scope.private1=12;
                $scope.private2=22;
                $scope.test=123;
            }]);
    var template=angular.module("template",[])
            .run(["$templateCache", function ($templateCache) {
                $templateCache.put("one.html","" +
                        "<div><input type='text' ng-model='$parent.private1'/></div>")
            }])
            .run(["$templateCache", function ($templateCache) {
                $templateCache.put("two.html","" +
                        "<div><input type='text' ng-model='$parent.private2'/>" +
                        "<div class='sco'><span>原始類型</span>{{test}}</div>" +
                        "</div>")
            }])
</script>
</html>

大家如果有什么疑問,歡迎提出來。<p>

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容