发表于: 2017-05-31 21:29:08
1 941
今天完成的事情:
AngularJS的两种类型的数据绑定。以及一些模板指令。重点ng-repeat。表格条纹化可看可不看,用BS就可以。还有一些事件指令,类似JS用法。
明天计划的事情:
看表单,控制器,再次看directive
遇到的问题:
虽然在整理基础知识,但还是没有搞定directive
收获:
关于数据绑定指令
执行和禁止单向绑定
AngularJS支持两种类型的数据绑定。第一种是单向绑定,即从数据模型中获得值并插入到HTML元素中。
ng-bind指令负责创建单向数据绑定,但很少直接使用它(看到他多用了一个span),因为AngularJS在HTML文档中遇到{{}},也会创建这种绑定。AngularJS允许你修改用于内联绑定的字符。
tip:你只能对那些被控制器添加到$scope对象中的数据创建绑定。
除了使用起来不太顺手,ng-bind还受限与只能处理单个数据绑定表达式。如果要创建多个数据绑定,就应该使用ng-bind-template。不过用ng-bind-template的情况也很少。
例子如下,但是ng-bind和{{}}不能一起用,有错误的。要一起用就得用ng-bind-template
关于ng-non-bindable
内联绑定的缺点是AngularJS将寻找并处理内容中的每一对{{和}}括号。这可能成为问题,特别是在混用JavaScript工具包并想在HTML的某部分上使用一些其他模板系统(或者只是想在文本中使用双括号)。解决办法是使用ng-non-bindable,可以阻止AngularJS处理内联绑定。
AngularJS不是唯一使用{{和}}的JavaScript包,因此如果同时使用多个库时可能会遇到问题。AngularJS允许你修改用于内联绑定的字符。
如果没有使用ng-non-bindable指令,AngularJS将处理div元素的内容并试图绑定到名为and的模型属性。在请求绑定一个不存在的模型属性时,AngularJS也不会报错,因为他假定这个属性将会在之后创建(这个在ng-model中解释)。所以相应的,他根本不会插入任何内容。
创建双向数据绑定
双向数据绑定会从两个方向同时跟踪变化,允许元素从用户处收集数据以修改程序的状态。双向绑定通过ng-model指令创建。
上面的例子中有两个数据绑定,都是绑定到todos数据数组中的第一个对象的action属性上(改属性使用控制器中的$scope对象建立的,在绑定中通过todos[0].action引用)。第一个绑定是一个内联的单向绑定。第二个绑定是通过input元素使用的,是一个双向绑定。
双向绑定仅能应用于那些允许用户输入数据值的元素上,也就是input、textarea和select元素。ng-model指令对所应用到的元素的内容进行设置,也通过更新数据模型的方式响应用户所做的修改。
tip:双向绑定并不是真的有多么神奇。当input元素的内容被修改时,AngularJS使用标准JavaScript时间从input元素接受通知,并且将这一变化通过$scope服务进行传播。你可以通过F12开发者工具看到AngJS所建立的时间处理器。
使用模板指令
这是使用ng-repeat指令最简单而常见的方式:使用一个对象集合为table元素生成若干行。使用ng-repeat指令的方法可分为两部分:第一部分是指定数据对象源以及在模板中要处理的对象被引用的名称
<tr ng-repeat="item in todos">
ng-repeat指令属性值的基本形式是<variable>in<source>,其中source是被控制器的$scope所定义的一个对象或数组,在本例中是todos数组。该指令遍历数组中的对象,创建元素及其内容的一个新实例,并且处理所包含的模板。在指令属性值中赋给<variable>的名称可以用于引用当前数据对象。在本例中,使用了变量名item:(在chrome中右键查看网页源代码和按F12看是不一样的)
重复操作对象属性
通过ng-repeat指令来内嵌使用。
外层的ng-repeat指令对todos数组中的每个对象生成一个tr元素,而且每个对象被赋给变量item。内层ng-repeat指令对每个属性生成一个td元素并将属性值赋给变量prop。最后,prop变量用于一个单向数据绑定,作为td元素的内容。
(就是一层一层剥出来,一个数组里面剥对象,一个对象里面剥属性)
这以上两个例子生成的内容是相同的,但是却能够自适应地为数据对象中定义的任何新属性生成td元素。
使用数据对象的键值进行工作
对于ng-repeat指令的配置有一个可供替代的语法选项,允许你从被处理的每个属性或者数据对象中接受一个键值
与单个变量名(item in items中的item或者说是prop)不同的是,我指定了被一对圆括号包括并以逗号分隔的两个名称。对ng-repeat指令所遍历的每个对象或者属性来说,第二个变量将被赋以数据对象或者属性值。第一个变量的使用方式则依赖于数据源(其实就是如果in 后面的是[{}],那么就是{}。如果是对象,那么就遍历属性。一层层往里剥,细化,遍历)。对于对象,key是当前属性名,而对于集合,key则是当前对象所处的位置。对于上面例子中所遍历的是一个对象的属性,所以key的值是属性名,而value将被赋以属性值。
如下
使用内置变量工作
ng-repeat指令将当前对象或者属性赋给你所指定的变量,但是还有一组内置变量($index)可用于提供被处理数据的上下文信息。
先向包含todo项目的表格中增添了一列,并使用到了ng-repeat指令提供的$index变量来显示数组中每项的位置。由于JavaScript集合的索引式从0起始的,所以向$index+1用来表示实际位置,AngularJS将会在数据绑定中计算这些JavaScript表达式。
$index是一个最为有用的一个变量
当然除了$index还有其他
使用了ng-class指令来设置使用了数据绑定的元素的class属性。用到一个三元JavaScript表达式根据$odd变量的值来对元素的class属性值赋以odd或者even。
tip:(这里以后介绍ng-class指令以及两个经常与ng-repeat使用的相关指令:ng-class-even和ng-class-odd。这些指令根据ng-repeat指令定义的$odd和$even变量设置class属性的值)
重复生成多个顶层元素
ng-repeat指令对所处理的对象或属性重复生成一个顶层元素及其内容。尽管如此,有时候也需要对每个数据对象重复生成多个顶层元素。在需要对每个处理的数据项生成多个表格行时最常遇到这种问题-这很难用ng-repeat指令解决,因为在tr元素机器父元素之间不允许使用任何中间元素。要解决这个问题就可以使用ng-repeat-start和ng-repeat-end指令。
ng-repeat-start指令的配置方法类似于ng-repeat,但是将会重复生成所有的顶层元素知道ng-repeat-end属性所应用到的元素(包含在内)(就是自定义类似ng-repeat这是怎么一个循环的。)
使用局部视图工作
ng-include指令从服务器获取一段HTML片段,编译并处理其中包含的任何指令,并添加到DOM中去。这些片段被称为局部视图。
但出现报错,暂时不管这个ng-include了
使用了ng-show和ng-hide指令来控制表格中每行最后一格中的span元素的可见性。这个例子其实可以通过内联数据绑定达到同样的效果,但是我们需要的是一个能够演示特定问题的例子。
ng-show和ng-hide指令通过添加和移除一个名为ng-hide(容易与指令名混淆)的CSS类来控制元素的可见性。ng-hide这个类的CSS样式将display属性设为none,从而从视图中移除该元素。ng-show与ng-hide之间的区别在于,ng-show在表达式值计算为false时隐藏元素,而ng-hide在表达式值为true时隐藏元素。
td > *:first-child {font-weight: bold;color: red;}
你将会看到td元素的第一个子元素应该为粗体
你将会看到这个样式只会在to-do项未完成时起作用,即使我已经指定了td元素的第一个子元素应该为粗体。
这个问题的原因在于ng-show和ng-hide指令仍会将所操作的元素保留在DOM中,仅仅是对用户隐藏。对浏览器来说他们并没有隐藏,仍然在那儿。因此类似这种根据位置进行选择的CSS选择器将会把隐藏元素也计算在内。在这种情况下,你可以使用ng-if指令从COM(不是DOM) 中移除元素,而不是隐藏元素
对于ng-if来说没有方便的逆指令,因此必须对被绑定的属性进行取反,加个!.来创建ng-hide指令的效果。
这样就解决了CSS样式的问题。
解决表格的条纹化问题以及与ng-repeat的冲突
ng-show、ng-hide与ng-if指令在应用到组成表格的元素时都有一些问题,这有些令人遗憾,因为AngularJS的新开发着经常试图使用这些指令管理表格中显示的内容。
首先,ng-show与ng-hide的工作方式意味着他们无法容易地在条纹化的表格中所使用。这个例子前面有过演示。还有个新例子。
AngularJS将处理这些指令,但是因为这些元素是被隐藏而不是被移除,所以结果会造成条纹显示得不一致。
这看起来似乎能通过有ng-if指令解决,但是你无法在ng-repeat指令所应用到的同一个元素上使用ng-if指令。
ng-repeat和ng-if指令都依赖于叫做嵌入包含的技术,基本意思是说两个指令都想修改子元素,而AngularJS无法知道怎样让两者都能做到。就是会报错。(不过我在实践中没发现有错误,应该是Angular版本问题)
在ng-repeat中的settings中他的顺序是按字母顺序而不是你给定的顺序!!这里是为什么?
本例核心是想控制器作用域增加一个简单的对象。
我们使用Row属性来设置表格tr元素的背景色,并使用Columns属性设置Done一列的背景色。为了让用户能够设置这些值,我是用了ng-repeat指令创建了两组单选框按钮,按照bootstrap网格样式进行布局。使用了ng-class指令来为tr元素设置元素。
ng-class指令可以管理一个元素的class属性。在本例中根据Rows属性的值,tr元素会被添加到一个CSS类中,对应的CSS样式定义如下:
(tip:你可以使用一个map对象指定多个CSS类,该对象中的属性涉及这些CSS类,其值是用于控制将使用哪些CSS类的表达式。)
通过使用ng-style属性来直接设置CSS属性,而不是通过一个CSS类:
ng-style指令被配置为使用一个对象,该对象的属性为相应的应设置的CSS属性-在这里即使background-color属性,将会被设置为Columns模型属性的当前值。
tip:一般认为对元素使用某个单独的CSS属性并不是好方法。当使用静态内容时,通过CSS类来使用的样式更为容易使用,至少不会是最差的选择,因为对样式定义的一处修改能够被应用于任何该样式所使用到的地方。在使用ng-style指令时的情形有些许不同,因为属性的值是从数据绑定中获得的,通常额指导方法并不适合,我的建议是在能够使用CSS类的时候就尽量用,当时并没有必要对ng-style指令避而不用。
设置奇数行和偶数行的CSS类
ng-class指令的另一变体是由ng-class-odd和ng-class-even指令提供的,在ng-repeat指令中使用这两个指令,并仅对奇数行或偶数行的元素应用CSS类。这和使用$odd和$even等所提到的ng-repeat内置变量是类似的。
仅当在ng-rep指令中的元素为偶数序号时,ng-cla-even指令才会对其所使用到的元素的class属性应用数据绑定。同样,仅当元素为奇数序号时,ng-class-odd指令才会修改钙元素。通过在同一个元素上使用这些指令,不需要使用Bootstrap也能够创建出经典的条纹效果表格。
如果在使用类似Bootstrap这样的CSS框架时,这些指令并不是非常有用,但是条文化的表格是如此常见的一种需求,几乎每种JavaScript工具包都提供了对某种条纹效果的支持
处理事件
虽然AngularJS提供了一组事件指令,但是你会发现能够创建的时间处理器仍然比通过jQuery所创建的要少。这是因为Web程序中的许多有趣的时间是在用户改变表单元素的状态时产生的,比如input和select。在AngularJS中你不需要通过时间响应这些变化,因为你可以使用ng-model指令代替。时间处理器仍然在后台被AngularJS所使用,但是你不需要自己编写和管理他们。
有的开发者对在元素上使用时间之灵感到不适应,特别是当其包含内联表达式时。这种不适应来自两个原因:一是仅仅因为不习惯,另一个则有值得探讨的价值。
常见的原因是因为Web开发者乐于频繁地使用不太引人注意的JavaScript来创建事件处理器,而不是直接在元素上添加代码。这并不是AngularJS所担心的事,他也用了jQuery在背后创建一些不太引人注意的处理器。在元素上使用事件让人感觉有点奇怪,但是却不会带来那些背后的JavaScript所需要极力避免的维护问题。
有探讨价值的是结合指令使用表达式的想法,而不是对控制器行为的依赖。我不喜欢在视图中看到除了最简单的逻辑以外的任何东西,而且更偏爱于使用控制器行为。为了防止滥用表达式,要知道在AngularJS视图中者要少得多,因为大量依赖了ng-repeat这样的指令来生成元素,但使用表达式仍然容易导致创建出不好测试和维护的代码。我的建议是尽量使用事件指令,但是将触发事件时所执行的逻辑放到控制器行为中。
评论