2016年之后的前端框架都使用了 Object.defineProperties 以忣类似的原生技术作为底层实现双向数据绑定。但是我查阅MDN后发…
本篇文章主要的介绍了和angularjs数据绑萣4的区别还有使用angular4的好处详情。下面就让我们一起来看这篇文章吧
1本身的脏值检查机制,当页面数据发生变化时就会触发检查机制,当页面绑定的数据越来越多时就会造成程式不断的去触发脏值检查机制,程序的相应就会越来越慢
2.路由子路由不可嵌套,提供了一個第三方解决方式uirouter,但是使用起来非常不稳定
3.作用域$scope作用域的限制,使得很多原生的事件不能使用比如click事件,必须使用指令来实现
4.表单校验的时候必须写一个指令来提示错误信息很麻烦
2.服务器端渲染,可以使10S加载完成的单页应用1S加载完成还可以针对每一个人视图去做SEO優化
3.移动端和桌面端兼容。创建跨平台应用手机应用,提供了可以在移动端和桌面端通用的ui组件
(想看更多就到PHP中文网中学习)
1.虚拟DOM速度响应很快,
2.flux架构实现服务器端渲染
3.本身只是MVC中的V层,常需要和其他库结合使用重点在UI上
而angular满足上述所有优点
4.个人主导的(angular类似生態圈,vue类似社区vue由国内大牛开发angular谷歌团队开发)
5.服务器端渲染,vue只能借助其他服务器渲染库
本篇文章到这就结束了(想看更多就到PHP中文網中学习)有问题的可以在下方留言提问。
以上就是为什么使用angular4angularjs数据绑定和angular4的区别的详细内容,更多请关注php中文网其它相关文章!
这篇是对angularjs数据绑定的一些疑点回顧是对目前angularjs数据绑定开发的各种常见问题的整理汇总。如果对文中的题目全部了然于胸觉得对整个angular框架应该掌握的七七八八了。希望誌同道合的通知补充内容
脏检查机制阐释脏检查机制,必须先了解如下问题
两者的区别在于页媔没有加载完毕 {{val}} 会直接显示到页面,直到 Angular 渲染该绑定数据(这种行为有可能将 {{val}} 让用户看到);而 ng-bind 则是在 Angular 渲染完毕后将数据显示
双向数据綁定是 angularjs数据绑定 的核心机制之一。当 view 中有任何数据变化时会更新到 model ,当 model 中数据有变化时view 也会同步更新,显然这需要一个监控。
当你寫下表达式如{{ val }}时angularjs数据绑定在幕后会为你在scope模型上设置一个watcher(表达式将被 Angular 编译成一个监视函数),它用来在数据发生变化的时候更新view这裏的watcher和你会在angularjs数据绑定中设置的watcher是一样的:
将数据附加到 Scope 上,数据自身不会对性能产生影响如果没有监视器来监视这个属性,那个这个屬性在不在 Scope 上是无关重要的;Angular 并不会遍历 Scope 上的属性它将遍历所有的观察器。
每个监视函数是在每次 $digest 过程中被调用的因此,我们要注意觀察器的数量以及每个监视函数或者监视表达式的性能
click 时会产生一次更新的操作(至少触发两次 $digest 循环)
在调用了$scope.$digest()后$digest循环就开始了。假设你在一个ng-click指令对应的handler函数中更改了scope中的一条数据此时angularjs数据绑定会自动地通过调用$digest()来触发一轮$digest循環。当$digest循环开始后它会触发每个watcher。这些watchers会检查scope中的当前model值是否和上一次计算得到的model值不同如果不同,那么对应的回调函数会被执行調用该函数的结果,就是view中的表达式内容(译注:诸如{{
通常写代码时我们无需主动调用 $apply 或 $digest 是因为 angular 在外部对我们的回调函数做了包装例如常鼡的 ng-click,这是一个指令(Directive)内部实现则 类似 于
可以看到:ng-click 帮我们做了 $apply 这个操作。类似的不只是这些事件回调函数还有 $http、$timeout 等。我听很多人菢怨说 angular 这个库太大了什么都管其实你可以不用它自带的这些服务(Service),只要你记得手工调用 $scope.$apply
function中,然后传入到$scope.$apply()因此,你的function会正常被执荇修改models(如果需要的话),此时一轮$digest循环也会被触发用来确保view也会被更新。
$digest 循环的上限是 10 次(超过 10次后抛出一个异常,防止无限循环)
$digest 循环不会只运行一次。在当前的一次循环结束后它会再执行一次循环用来检查是否有 models 发生了变化。
这就是脏检查(Dirty Checking)它用来处理在 listener 函数被执行时可能引起的 model 变化。因此 $digest 循环会持续运行直到 model 不再发生变化或者 $digest 循环的次数达到了 10 次(超过 10 次后抛出一个異常,防止无限循环)
angular 会在可能触发 UI 变更的时候进行脏检查:这句话并不准确。实际上
脏检查是digest执行的,另一个更常用的用于触发脏檢查的函数apply——其实就是 $digest 的一个简单封装(还做了一些抓异常的工作)
通常写代码时我们无需主动调用 $apply 或 $digest 是因为 angular 在外部对我们的回调函數做了包装。例如常用的 ng-click这是一个指令(Directive),内部实现则 类似于
angular对常用的dom事件xhq事件作了封装,如果调用这些封装就会在里面触发进叺angular的digest流程,主要有以下情况:
DOM事件如用户输入文本,点击按钮等(ng-click)
$apply 是 $scope(或者是 direcvie 里的 link 函数中的 scope)的一个函数,调用它会强制一次 $digest 循环(除非当前正在执行循环这种情况下会抛出一个异常,这是我们不需要在那里执行 $apply 的标志)
1) 最直接的差异是, $apply 可以带参数它可以接受一个函数,然后在应用数据之后调用这个函数。所以一般在集成非 Angular 框架(比如jQuery)的代码时,可以把代码写在这个里面调用
2) 当調用 $digest 的时候,只触发当前作用域和它的子作用域上的监控但是当调用 $apply 的时候,会触发作用域树上的所有监控
angularjs數据绑定对此有着非常明确的要求就是它只负责对发生于angularjs数据绑定上下文环境中的变更会做出自动地响应(即,在$apply()方法中发生的对于models的更妀)angularjs数据绑定的built-in指令就是这样做的,所以任何的model变更都会被反映到view中但是,如果你在angularjs数据绑定上下文之外的任何地方修改了model那么你就需要通过手动调用$apply()来通知angularjs数据绑定。这就像告诉angularjs数据绑定你修改了一些models,希望angularjs数据绑定帮你触发watchers来做出正确的响应
典型的需要调用 $apply() 方法的场景是:
运行这个例子,会看到过了两秒钟之后控制台确实会显示出已经更新的 model,然而view 并没有更新。
实现一个 click 的指令类似以下功能,directive 的编写如下:
跟场景一的结果一样,这个时候点击按钮,界面上的数字并不会增加但查看调试器,发现数据确实已经增加了
想潒一下如果有个 alert 框显示错误给用户,然后有个第三方的库进行一个网络调用然后失败了如果不把它封装进 $apply 里面,Angular 永远不会知道失败了alert 框就永远不会弹出来了。
如果要监听的是一个对象那还需要第三个参数
表示比较的是对象的值而不是引用,如果不加第三个参数 true 在 data.name 变囮时,不会触发相应操作因为引用的是同一引用。
问:点击 TEST 这个按钮时会触发脏检查吗触发几次?
首先:ng-click="" 什么都没有做angular 会因为这个倳件回调函数什么都没做就不进行脏检查吗?不会
然后:#span1 被隐藏掉了,会检查绑定在它上面的表达式吗尽管用户看不到,但是 $scope.$watch('content', callback) 还在僦算你直接把这个 span 元素干掉,只要 watch 表达式还在要检查的还会检查。
再次:重复的表达式会重复检查吗会。
最后:别忘了 ng-show="false"可能是因为 angular 嘚开发人员认为这种绑定常量的情况并不多见,所以 $watch 并没有识别所监视的表达式是否是常量常量依旧会重复检查。
所以说一个绑定表达式只要放在当前 DOM 树里就会被监视不管它是否可见,不管它是否被放在另一个 Tab 里更不管它是否与用户操作相关。
里新引入的组件(Component)
所以说不要怀疑用户在输入表单时 angular 会不会监听页面左边导航栏的变化。
说实话脏检查效率是不高但是也谈不仩有多慢。简单的数字或字符串比较能有多慢呢十几个表达式的脏检查可以直接忽略不计;上百个也可以接受;成百上千个就有很大问題了。绑定大量表达式时请注意所绑定的表达式效率建议注意一下几点:
表达式(以及表达式所调用的函数)中少写太过复杂的逻辑
不偠连接太长的 filter(往往 filter 里都会遍历并且生成新数组)
不要访问 DOM 元素。
1、使用单次绑定减少绑定表达式数量单次绑定(One-time binding 是 Angular 1.3 就引入的一种特殊的表达式它以 :: 开头,当脏检查发现这种表达式的值不为 undefined 时就认为此表达式已经稳定并取消对此表达式的监视。这是一种行之有效的减少綁定表达式数量的方法与 ng-repeat 连用效果更佳(下文会提到),但过度使用也容易引发 bug
2、善用 ng-if 减少绑定表达式的数量
如果你认为 ng-if 就是另一种鼡于隐藏、显示 DOM 元素的方法你就大错特错了。
考虑这种 Tab 选项卡实现:
对于这种会反复隐藏、显示的元素通常人们第一反应都是使用 ng-show 或 ng-hide 简單的用 display: none 把元素设置为不可见。
首先 DOM 树中的元素个数显著减少至四分之一降低内存占用
其次 $watch 表达式也减少至四分之一,提升脏检查循环的速度
如果这个 tab 下面有 controller(例如每个 tab 都被封装为一个组件)那么仅当这个 tab 被选中时该 controller 才会执行,可以减少各页面的互相干扰
如果 controller 中调用接口獲取数据那么仅当对应 tab 被选中时才会加载,避免网络拥挤
DOM 重建本身费时间
如果在 controller 里面调接口获取数据那么每次该 tab 被选中时都会重新加載
不恰当的 ng-repeat 会造成 DOM 树反复重新构造,拖慢浏览器响应速度造成页面闪烁。除了上面这种比较极端的情况如果一个列表频繁拉取 Server 端数据洎刷新的话也一定要手工添加 track by,因为接口给前端的数据是不可能包含 $$hashKey 这种东西的于是结果就造成列表频繁的重建。
其实不必考虑那么多总之加上没坏处,至少可以避免 angular 生成 $$hashKey 这种奇奇怪怪的东西
很多人对Angular的脏检测机制感到不屑,推崇基于settergetter的观测机制,在我看来这只昰同一个事情的不同实现方式,并没有谁完全胜过谁两者是各有优劣的。
大家都知道在循环中批量添加DOM元素的时候,会推荐使用DocumentFragment为什么呢,因为如果每次都对DOM产生变更它都要修改DOM树的结构,性能影响大如果我们能先在文档碎片中把DOM结构创建好,然后整体添加到主攵档中这个DOM树的变更就会一次完成,性能会提高很多
同理,在Angular框架里考虑到这样的场景:
如果界面上某个文本绑定这个numOfCheckedItems,会怎样茬脏检测的机制下,这个过程毫无压力一次做完所有数据变更,然后整体应用到界面上这时候,基于setter的机制就惨了除非它也是像Angular这樣把批量操作延时到一次更新,否则性能会更低
所以说,两种不同的监控方式各有其优缺点,最好的办法是了解各自使用方式的差异考虑出它们性能的差异所在,在不同的业务场景中避开最容易造成性能瓶颈的用法。
第一点区别是ng-if 在后面表达式为 true 的时候才创建这個 dom 节点,ng-show 是初始时就创建了用 display:block 和 display:none 来控制显示和不显示。第二点区别是ng-if 会(隐式地)产生新作用域,ng-switch 、 ng-include 等会动态创建一块界面的也是如此
不可以。只要是在页面中就不能直接调用原生的 JS 方法,因为这些并不存在于与页面对应的 Controller 的 $scope 中除非在 $scope 中添加了这个函数:
使用方式有两种,一种是直接在页面里:
一种是在 js 里面用:
和 service 功能类似只不过 factory 昰普通 function,可以返回任何东西(return 的都可以被访问所以那些私有变量怎么写你懂的);service 是构造器,可以不返回(绑定到 this 的都可以被访问);provider 昰加强版 factory返回一个可配置的 factory。
angularjs数据绑定 是通过构造函数的参数名字来推断依赖服务名称的通过 toString() 来找到这个定义的 function 對应的字符串,然后用正则解析出其中的参数(依赖项)再去依赖映射中取到对应的依赖,实例化之后传入因为 angularjs数据绑定 的 injector 是假设函數的参数名就是依赖的名字,然后去查找依赖项那如果像下面这样简单注入依赖,代码压缩后(参数被重命名了)就无法查找到依赖項了。
所以通常会使用下面两种方式注入依赖(对依赖添加的顺序有要求)。
对于一个 DI 容器必须具备三个要素:依赖项的注册,依赖關系的声明和对象的获取在 angularjs数据绑定 中,module 和 $provide 都可以提供依赖项的注册;内置的 injector 可以获取对象(自动完成依赖注入);依赖关系的声明僦是上面的那两种方式。
有问题时间是实时变化的,然后会一直更新数据效率低,脏数据检查到10次之后不再继续检查;
解决方案:可以使用一个变量来接收函数调用
指代清晰在嵌套scope时,子scope如果想使用父scope的属性只需简单的使用父scope的别名引用父scope即可。
as的一大好处就是原型鏈继承给scope带来的问题都不复存在了即有效避免了在嵌套scope的情况下子scope的属性隐藏掉父scope属性的情况。)
定义controller时不用显式的依赖$scope这有什么好處呢?仔细看定义这不就是一个普通的函数定义嘛,对!这就是好处!例子中的ScopeController就是所谓的POJO(Plain Old Javascript ObjectJava里偷来的概念),这样的Object与框架无关裏面只有逻辑。所以即便有一天你的项目不再使用angularjs数据绑定了依然可以很方便的重用和移植这些逻辑。另外从测试的角度看,这样的Object吔是单元测试友好的单元测试强调的就是孤立其他依赖元素,而POJO恰恰满足这个条件可以单纯的去测试这个函数的输入输出,而不用费勁的去模拟一个假的$scope
防止滥用$scope的$watch,$on$broadcast方法。可能刚刚就有人想问了不依赖$scope我怎么watch一个model,怎样广播和响应事件答案是没法弄,这些事還真是只有$scope能干但很多时候在controller里watch一个model是很多余的,这样做会明显的降低性能所以,当你本来就依赖$scope的时候你会习惯性的调用这些方法来实现自己的逻辑。但当使用controller as的时候由于没有直接依赖$scope,使用watch前你会稍加斟酌没准就思考到了别的实现方式了呢。
个人觉得还是偏姠于使用controller as的当然有一点要澄清,使用contoller as并没有什么性能上的提升仅仅是一种好的习惯罢了。
angularjs数据绑定里比较重要但又很少手动调用的要屬$compile服务了通常在写组件或指令时,都是angularjs数据绑定自动编译完成的但有时我们可能需要手动编译,比如封装一个table组件根据参数实现自萣义渲染,增加一列复选框或者一列按钮啥的这是就需要用到$compile了。
$compile在Angular中即“编译”服务,它涉及到Angular应用的“编译”和“链接”两个阶段根据从DOM树遍历Angular的根节点(ng-app)和已构造完毕的 \$rootScope对象,依次解析根节点后代根据多种条件查找指令,并完成每个指令相关的操作(如指囹的作用域控制器绑定以及transclude等),最终返回每个指令的链接函数并将所有指令的链接函数合成为一个处理后的链接函数,返回给Angluar的bootstrap模塊最终启动整个应用程序。
先解说下angular中页面处理
ng对页面的处理过程:
浏览器把HTML字符串解析成DOM结构
传入具体的scope调用这个link函数
得到处理后的DOM这个DOM处理了指令,连接了数
$compile是个编译服务编译服务主要是为指令编译DOM元素。
编译一段HTML字符串或者DOM的模板产生一个将scope和模板连接到一起的函数。
element:将要被编译和插入模板的元素或者HTML字符串
maxPriority:只有在指令比给定的优先级低时应用只影响根元素,不影响子元素
通过$compile服务可鉯编译html字符串或dom对象或jqLite对象然后得到一个编译函数,再传入$scope就会在当前作用域进行编译,返回编译好的jqLite对象这时就可以直接添加到攵档中了(也可以先添加到文档再编译)。
编译的实质其实就是对dom对象解析使dom对象与scope进行耦合,通过绑定可以实现数据的更新像Vue其实吔是一样的过程。
这篇是对angularjs数据绑定的一些疑点回顾文章的问题大多是从网上搜集整理而来,如有不妥之处或不远被引用请通知本人修改,谢谢!
首发于转载注明来源:《》
(徐飞博客:由浅入深地阐释了angularjs数据绑定)