Ionic中的$scope的作用域问题(结合AngularJS的$scope作用域)

最近都在闲,好不容易可以轻松一下,就放心的玩了一个月。现在到公司实习了,正好接着做之前没有做完的事情。在使用Ionic框架的过程中还是遇到一些问题,就此记录一下。

关于Ionic框架,之前也写了一篇,记录的是遇到的一些小问题,这次这篇,和AngularJS有关。我们知道Ionic框架是基于AngularJS的,由AngularJS进行路由控制,数据交互,而Ionic只相当于一个UI框架。所以如果有AngularJS基础,学习这个框架其实不难。但是其中还是有一些不一样的地方,这篇要说的,就是Ionic中$scope的作用域问题。

问题描述

在Ionic应用中,HTML页面中ng-model绑定的数据,无法在controller中获取到。
详情如下:

<!--HTML代码中-->
<div class="item-input textarea-input">
        <textarea rows="4" ng-model="content" placeholder="说点什么吧..."></textarea>
</div>

//controller中
$scope.publish = function() {
    console.log($scope.content);
}

在这里控制台输出是undefined。问题就在这里,如果是在AngularJS中,这样写是完全没有问题的。

在此之前,先看一下AngularJS中controller的控制域,之前学习的时候只是简单的知道controller之间可以是平级关系,也可以是子父级关系,这取决于controller控制的html区域的关系,是否嵌套,所以对应的$scope的作用域也是可以嵌套的。

AngularJS的根作用域

每个AngularJS应用都有一个默认的根作用域$rootScope,如果没有指定控制器,那么ng-model绑定的数据就会自动绑定到$rootScope中。如果想要在controller中使用$rootScope绑定的数据,需要像$scope一样,注入到控制器中。

AngularJS中作用域的继承关系

作用域的继承是刚接触AngularJS的时候就了解到的内容了,但是一直没有深入了解,现在才回遇到这个问题。在html页面中的嵌套关系中,绑定上对应的controller,controller也就嵌套,这样一来,对应的作用域就有了继承关系。
如下:

<div ng-app="myApp" ng-controller="parentCtrl">
    <p>{{firstName}}</p>
    <div ng-controller="childCtrl">
        <p>{{firstName}}</p>
        <button ng-click="update()">点击修改</button>
    </div>
</div>

//js
app.controller('parentCtrl', function($scope) {
   $scope.firstName = "John";
});
app.controller('childCtrl', function($scope) {
    $scope.update = function() {

    }
});

由此,两个控制器中的$scope有了子父级关系,那么,哪些内容是可以继承的,哪些内容是共享的呢?

1.简单变量可继承

还是上面这个例子,写上按钮的点击事件:

<div ng-app="myApp" ng-controller="parentCtrl">
    <p>{{firstName}}</p>
    <div ng-controller="childCtrl">
        <p>{{firstName}}</p>
        <button ng-click="update()">点击修改</button>
    </div>
</div>

//js
app.controller('parentCtrl', function($scope) {
   $scope.firstName = "John";
});
app.controller('childCtrl', function($scope) {
    $scope.update = function() {
        $scope.firstName = $scope.firstName+"zzz";
    }
});

一开始,我们没有在childCtrl中声明firstName变量,但是childCtrl管辖范围内的还是显示出了这个变量值,就是从parentCtrl中继承而来的值,这和java的基础有点像,子类中找不到值,就去父类中找,发现父类中有这个值,就直接取来用,这里的隐式操作可以理解成这样,childCtrl.firstName = parentCtrl.firstName;

但是有一个问题,当我们点击按钮,修改firstName的值时,发现,只有子控制器中的值改了,父控制器内的没有变,这就是变量值的继承

2.对象在上下级作用域之间共享
<div ng-app="myApp" ng-controller="parentCtrl">
    <p>{{data.firstName}}</p>
    <div ng-controller="childCtrl">
        <p>{{data.firstName}}</p>
        <button ng-click="update()">点击修改</button>
    </div>
</div>

//js
app.controller('parentCtrl', function($scope) {
   // $scope.firstName = "John";
    $scope.data = {
        firstName:"John"
    }
});
    app.controller('childCtrl', function($scope) {
    $scope.update = function() {
        //$scope.firstName = $scope.firstName+"zzz";
        $scope.data.firstName = $scope.data.firstName+"zzz";
    }
});

这次结果就不一样了,再点击修改,上下级的变量值都会改变。因为两者的data对象是一个引用,对下级对象上值的修改可以反映到两级对象上。

3.$parent指定父级作用域

在子父级之间有变量继承时,很容易产生歧义,所以最好是指定不同的变量名,避免歧义,如果确实要使用“变量继承”,可以使用$parent,它是$scope的一个属性,可以用来指定父级作用域,使得子级作用域修改继承的变量时,可以同步映射到父级。

//修改子级作用域中的变量名,添加$parent来指定修改的值
<div ng-app="myApp" ng-controller="parentCtrl">
    <p>{{firstName}}</p>
    <div ng-controller="childCtrl">
        <p>{{firstName}}</p>
        <button ng-click="update()">点击修改</button>
    </div>
</div>

//js
app.controller('parentCtrl', function($scope) {
   $scope.firstName = "John";
});
app.controller('childCtrl', function($scope) {
    $scope.update = function() {
         $scope.$parent.firstName = firstName+"zzz";
    }
});

一些命令也会创建作用域

在AngularJS中,不止ng-controller会创建作用域,一些命令也会,如果不清楚作用域的关系,很容易出错。

ng-repeat

ng-repeat会创建自己的作用域其实很容易理解,ng-repeat范围内的每一项都是独立存在的,如下:

<div ng-app="myApp" ng-controller="myCtrl">
    {{sum}}
    <ul>
        <li ng-repeat="item in arr">
            {{item}}
            <button ng-click="item = item + 1">incerase</button>
        </li>
   </ul>
</div>

//js
app.controller('myCtrl', function($scope) {
    $scope.sum = 2;
    $scope.arr = [1,2,3];
});

上面这个例子,每个li里的item都是独立的,运行之后我们可以发现,虽然名字都一样,但是它们之间互不影响,这是因为它们各自有自己的作用域,我们可以再验证一下,如果在li标签内部改变sum的值会出现什么情况。

<div ng-app="myApp" ng-controller="myCtrl">
    {{sum}}
    <ul>
    <li ng-repeat="item in arr">
        {{item}}
        <button ng-click="sum = sum + 1">incerase</button>
        {{sum}}
        </li>
    </ul>
</div>

我们可以发现,li内部的sum的值改变了,但是列表外显示的sum值没有变化,这就是我们上面提到的,变量在作用域之间可继承,因为ng-repeat创建了自己的作用域,它使用的sum其实是继承自mgCtrl的,所以下级控制器改变sum的值不会影响上级的值。

如果想要改变外部的值,可以用$parent来指定上级sum的变化,这样一来,所有显示sum的地方都会变了,因为下级的sum都继承自上级。

<div ng-app="myApp" ng-controller="myCtrl">
    {{sum}}
    <ul>
    <li ng-repeat="item in arr">
        {{item}}
        <button ng-click="$parent.sum = sum + 1">incerase</button>
        {{sum}}
        </li>
    </ul>
</div>

之前的学习中一直觉得作用域和控制器时一样的,从上面的例子可以发现,两者还是不同,上面的作用域可以说是两级控制于,但是它们都处于一个控制器中。

ng-if

在刚接触AngularJS的时候,会接触到ng-showng-hide,这两个很好理解,就是满足条件的话就显示/隐藏,同样功能的还有ng-if,而二者的区别在于,ng-show和ng-hide的区域,原来就有,只是控制其是否显示,而ng-if是一开始没有,满足条件的话,才在DOM树中加入这块内容,我们可以在浏览器中用调试工具看到这个变化。

另外,它们还有一个区别,ng-if创建DOM的时候会为这块区域创建作用域,这样在使用的时候两者就有差别了,如果要访问外部的变量,就要像ng-repeat一样使用$parent了。

Ionic的问题

现在回到我们最初的问题?在Ionic框架中,有时候在使用ng-model在视图中绑定model之后,在controller中获取不到值,但是,如果在controller中定义了这个model的值,视图中是可以显示出来的,这是不是和上面提到的变量在作用域之间可继承很像呢?下级可以获取上级的,而上级获取不到下级的值。也就是说,ionic的某个命令创建了自己的作用域,在我们显示定义的作用域的下级。

一般情况下,我们会为一个模板文件绑定一个控制器,控制器自然会创建一个作用域,而这个默认文件的最上层是 ion-view命令,内容写在ion-content中,那是不是ion-content创建了作用域呢,我们可以这样来证明:

<ion-view ng-controller="myCtrl">
    <ion-header-bar align-title="center" class="bar-stable">
    <div class="buttons">
        <button class="button button-clear button-positive" ng-disabled="!$parent.ontent || $parent.content === ''" ng-click="publish()">
        发表
        </button>
    </div>
    </ion-header-bar>
    <ion-content>
        <div class="item-input textarea-input">
            <textarea rows="4" ng-model="$parent.content" placeholder="说点什么吧..."></textarea>
        </div>
    </ion-content>
</ion-view>

app.controller('PublishRcdCtrl', ['$scope', function($scope) {
    $scope.publish = function() {
        console.log($scope.content);
    }
}])

上面这个例子,当我在textarea中绑定的是content的时候,点击ion-header-bar里的按钮是不会打印出输入的内容的,所以我在输入框上绑定了$parent.content,然后按钮上的ng-disabled命令绑定的也是$parent.content,这时,不管输入框中有没有内容,按钮都显示被禁用,然后我把ng-disable命令绑定到content上,按钮就可以正常使用了。两个地方使用content变量的获取方式不同,这也说明了是ion-content指令创建了作用域,这也说明了为什么我能在ion-footer-bar中正常进行数据双向绑定了,因为它不会创建作用域。

解决方法,来自上面的说明,可以使用$parent,也可以上下级作用域共享对象,也有的方法说的是,显示指定ng-controller,我试过这个方法,但是没有生效,可能是使用环境不对,大家都可以试一试。

总结

果然知识没学透,很多麻烦都会自己找来的,这里推荐一篇 大神的博客 ,我也是看了别人写的文章之后才懂的,加上了自己的理解。好了,就到这里了,遇到问题再更。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,732评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,496评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,264评论 0 338
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,807评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,806评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,675评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,029评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,683评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 41,704评论 1 299
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,666评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,773评论 1 332
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,413评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,016评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,978评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,204评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,083评论 2 350
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,503评论 2 343

推荐阅读更多精彩内容

  • AngularJS 常见面试问题 1. ng-if 跟 ng-show/hide 的区别有哪些? ng-if在后面...
    darr250阅读 2,689评论 0 11
  • 2013年8月2日, 严清 译译文:理解AngularJS的作用域Scope原文:Understanding Sc...
    竿牍阅读 361评论 0 0
  • 个人博客搭建完成,欢迎大家来访问哦黎默丶lymoo的博客 博主最近了解学习了一下angularJS,记录一下心得给...
    黎默丶lymoo阅读 1,029评论 0 21
  • AngularJS是什么?AngularJs(后面就简称ng了)是一个用于设计动态web应用的结构框架。首先,它是...
    200813阅读 1,588评论 0 3
  • 翻译自:Understanding Scopes 摘要 在AngularJS中,子作用域通常会原型继承于其父作用域...
    paradisefj阅读 996评论 0 5