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

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

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

问题描述

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


//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也就嵌套,这样一来,对应的作用域就有了继承关系。
如下:

{{firstName}}

{{firstName}}

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

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

1.简单变量可继承

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

{{firstName}}

{{firstName}}

//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.对象在上下级作用域之间共享

{{data.firstName}}

{{data.firstName}}

//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来指定修改的值

{{firstName}}

{{firstName}}

//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范围内的每一项都是独立存在的,如下:

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

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

{{sum}}
  • {{item}} {{sum}}

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

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

{{sum}}
  • {{item}} {{sum}}

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

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创建了作用域呢,我们可以这样来证明:


    
    
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,我试过这个方法,但是没有生效,可能是使用环境不对,大家都可以试一试。

总结

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

你可能感兴趣的:(Ionic中的$scope的作用域问题(结合AngularJS的$scope作用域))