
解决angularjs中post参数获取不到的问题的方法:
当使用angularjs发送post请求时:
1 $>
变更检测就是Angular检测视图与数据模型之间绑定的值是否发生了改变,当检测到模型中绑定的值发生改变时,就把数据同步到视图上。
我们先看下面这个例子
通过以上例子我们可以总结出来,在异步事件发生的时候可能会使数据模型发生变化。可是angular是如何检测到异步事件发生了呢?这还要说起zonejs。
官方定义zonejs是javascript的线程本地存储技术,猛地一听感觉好高大上,其实zonejs就是一种用来拦截和跟踪异步工作,为JavaScript提供执行上下文的插件。
那么它是如何感知到异步事件呢,其实方法相当简单粗暴,zonejs采用一种叫做猴子补丁 (Monkey-patched)的方式,将JavaScript中的异步任务都进行了包装,这使得这些异步任务都能运行在Zone(一个全局的对象,用来配置有关如何拦截和跟踪异步回调的规则)的执行上下文中,每个异步任务在 Zone 中都是一个任务(Task),除了提供了一些供开发者使用的钩子外,默认情况下Zone重写了以下方法:
zonejs部分源码
通过打印window对象我们可以发现zonejs对异步方法进行了封装,非异步方法并没有处理。
zonejs本身比较庞大复杂,这里不做深入研究,对它的原理感兴趣的可以看一下这篇文章-zonejs。我们这里主要是了解它是怎么配合Angular工作的即可。
在 Angular 源码中,有一个 ApplicationRef 类,其作用是当异步事件结束的时候由 onMicrotaskEmpty执行一个 tick 方法 提示 Angular 执行变更检测及更新视图。
调用tick方法。其中this_zone 是NgZone 的一个实例, NgZone 是对zonejs的一个简单封装。
tick函数对所有附在 ApplicationRef上的视图进行脏检查。
Ok,我们现在已经知道Angular怎么监听异步事件了,那么当监测到异步事件后是怎么判断是否需要更新视图呢?其实比较简单,Angular通过脏检查来判断是否需要更新视图。脏检查其实就是存储所有变量的值,每当可能有变量发生变化需要检查时,就将所有变量的旧值跟新值进行比较,不相等就说明检测到变化,需要更新对应视图。当然,实际情况肯定不是这么简单,Angular会通过自己的算法来对数据进行检查,对算法感兴趣的可以参考这篇文章-Angular的脏检查算法。
Angular 应用是一个响应系统,首次检测时会检查所有的组件,其他的变化检测则总是从根组件到子组件这样一个从上到下的顺序开始执行,它是一棵线性的有向树,任何数据都是从顶部往底部流动,即单向数据流。怎么证明呢?看这个例子
运行以后我们会得到如下结果,可以看到首次检测时检查了所有组件,包括ReferComponent,检测从上到下逐个检测。点击改名按钮后再次检测时则只检测有变化的那一侧组件(RankParentComponent,RankChildrenComponent)。其中我们可以观察到,虽然在AppComponent中输入属性也发生了变化并且也更新了视图,但是ngOnChanges钩子却没有检测到变化,注意这是一个坑。
那么什么是单向数据流呢?其实简单理解就是angular检测到数据变化到更新完视图的过程中数据是不应该被改变的,如果我们在这期间更改了数据,Angular便会抛出一个错误,举个例子,我们在RankChildrenComponent的ngAfterViewChecked钩子函数中更改childName的值,在控制台会看到如下错误。
如果必须要更改这个属性的值,能不能做呢?答案是可以的。结合刚次提到的单向数据流,如果我们把这次数据变更放到下一轮Angular变更检测中,就能解决这个问题了。怎么做呢?刻意异步一下就行了。是不是很神奇?
至于angular为什么要采用单向数据流,其实也很好理解,最主要的就是防止数据模型和视图不统一,同时也可以提高渲染的性能。
讲了这么多,所以到底有什么用呢?其实在 Angular 中,每一个组件都都它自己的检测器(detector),用于负责检查其自身模板上绑定的变量。所以每一个组件都可以独立地决定是否进行脏检查。默认情况下,变化检测系统将会走遍整棵树(defalut策略),但我们可以使用OnPush变化检测策略,利用 ChangeDetectorRef实例提供的方法,来实现局部的变化检测,最终提高系统的整体性能。
来,举个例子。在ReferComponent中,我们设个定时器2秒以后更新一个非输入属性的值,在默认策略时,可以发现2秒以后视图中的值发生了改变,但是当我们把策略改为Onpush时,除了在AppComponent点击按钮改变输入属性justRefer外,其他属性改变不会引起视图更新,ReferComponent组件的检测也被略过。我们可以这么总结:OnPush 策略下,若输入属性没有发生变化,组件的变化检测将会被跳过。
可是我就是要更改非输入属性怎么办呢?别急,Angular早就为你想好了。在Angular中,有这么一个class:ChangeDetectorRef ,它是组件的变化检测器的引用,我们可以在组件中的通过依赖注入的方式来获取该对象,来手动控制组件的变化检测行为。它提供了以下方法供我们调用
现在我们来试试解决刚才那个问题,我们对ReferComponent做如下改造。
ok,现在看到在Onpush策略下手动修改非输入属性的值,视图也可以及时更新了。其他的几个方法也都大同小异,感兴趣的可以逐个试试。
var appData = [
{
name: 'C++从入门到放弃',
author: 'dreamapple',
books: [
{name: 'github'},
{name: 'google'},
{name: 'nodejs'},
{name: 'react'}
]
},
{
name: 'Java从入门到跑路',
author: '呵呵哒',
books: [
{name: '雪碧'},
{name: '百事可乐'},
{name: '鸡尾酒'}
]
}
];
现在有这么一个要求,我需要将上面的那个 appData
循环出来,其中还要循环出来 books
里面的每一项,然后每一个 books
里面的每一项都可以进行删除,也可以给每一个 books
数组里面添加新的一项。
(1)循环出来这个 appData
数据还是很容易的,通过嵌套的 ngRepeat
很方便的就可以搞定了。
(2)关于嵌套我们能够使用的索引是 $index
,但是两层以上的话,如果每一层嵌套都使用 $index
作为索引的话,势必会引起混乱。这个时候就需要我们想一些办法去得到每一层的索引。
(3)我们目前比较好的一个做法就是通过 ngInit
指令,然后在循环开始的时候将每一层的索引保存在一个变量中,然后就可以在循环的不同层级之间使用了。
(4)我们还需要定义另一个数组 vmtempItem
,这个数组也用于循环,循环出来的每一项用作被添加项的数据模型。
注意:循环 books
数组我们还有一些需要注意的地方,我们要使用 track by
语法,不然每次增加或者删除 books
里面的内容时, books
每一项的 $index
不会发生变化,那么就不好进行删除 *** 作了。
我把里面的重点部分单独拿了出来,然后大家一起来看一看:页面部分:
<ul class="list-group" ng-repeat="item in vmappData" ng-init="outerIndex = $index">
<h3>{{itemname}}<span class="outer-index">outerIndex:{{outerIndex}}</span></h3>
<h4>{{itemauthor}}</h4>
<li class="list-group-item">
<ul class="list-group">
<li class="list-group-item" ng-repeat="v in itembooks track by $index" ng-init="innerIndex = $index">
{{vname}} <span class="inner-index">innerIndex:{{innerIndex}}</span><button class="btn btn-danger" ng-click="vmremoveItem(outerIndex, innerIndex)">删除</button>
</li>
<li class="list-group-item">
<form class="form-inline">
<input class="form-control" ng-model="vmtempItem[$index]" type="text">
<button class="btn btn-primary" ng-click="vmaddItem(outerIndex)">添加一项</button>
</form>
</li>
</ul>
</li>
<hr ng-show="!$last">
</ul>
控制器部分:
function removeItem(outerIndex, innerIndex) {
vmappData[outerIndex]bookssplice(innerIndex, 1);
}
我们可以先看控制器里面的函数, removeItem
这个函数有两个参数,一个是 outerIndex
,一个是 innerIndex
,其中 outerIndex
表示的是第一层循环的 $index
索引, innerIndex
表示的是第二层的 $index
索引。每次删除一项我们都需要知道是删除第一层循环中哪一个对象中的哪一项。
在页面中我们通过 ng-init="outerIndex = $index"
保存了第一层循环的 $index
,通过使用 ng-init="innerIndex = $index"
保存了第二层循环的 $index
。所以接下来的 *** 作都很方便了。
如果对我上面所说的还没有很好理解的话,你可以尝试自己练习一下。下面是源码部分:
HTML部分
<head>
<meta charset="UTF-8">
<title>1</title>
<link rel="stylesheet" href=">
以上就是关于angular httpClient访问的请求的时候headers挂不上数据全部的内容,包括:angular httpClient访问的请求的时候headers挂不上数据、问什么angular中$scope方法中的this不等于$scope谢谢大神、Angular中的变更检测等相关内容解答,如果想了解更多相关内容,可以关注我们,你们的支持是我们更新的动力!
欢迎分享,转载请注明来源:内存溢出
微信扫一扫
支付宝扫一扫
评论列表(0条)