企业🤖AI智能体构建引擎,智能编排和调试,一键部署,支持私有化部署方案 广告
# Angular指令 指令指令(directive)是Angular中一个很重要的概念,相当于一个自定义的HTML元素,在Angular官方文档中称它为HTML语言的DSL(特定领域语言)扩展。按照指令的使用场景和作用可以分为两种类型的指令: * 组件型指令(Component) * 装饰型器指令(Decorator), 它是在Angular 2.x中提出的概念,它们也同样可以使用于Angular1.x。组件型指令主要是为了将复杂而庞大的View分离,使得页面的View具有更强的可读性和维护性,实现“高内聚低耦合”和“分离关注点”的有效手段;而装饰器型指令则是为DOM添加行为,使其具有某种能力,如自动聚焦(autoFocus)、双向绑定、可点击(ngClick)、条件显示/隐藏(ngShow/ngHide)等能力,同时它也是链接Model和View之间的桥梁,保持View和Model的同步。在Angular中内置的大多数指令,是属于装饰器型指令,它们负责收集和创建$watch,然后利用Angular的“脏检查机制”保持View的同步。对于组件型指令和装饰器型指令的这两种区分是非常重要的,它们在写法、业务含义、适用范围等方面都有非常明显的区别,理解了它们,对于我们日常的指令开发也具有很好的指导作用。 ## 组件指令 组件型指令组件型指令是一个小型的、自封装和内聚的一个整体,它包含业务所需要显示的视图以及交互逻辑,比如:我们需要在首页放置一个登录框和一个FAQ列表,如果我们把它们都直接写在首页的视图和控制器中,那么首页的视图和控制器将会变得非常庞大,这样不利于我们的分工协作和页面的长期维护。这时候更好的方案应该是,把它们拆分成两个独立的内聚的指令login-panel和faq-list,然后分别将<login-panel></login-panel>和<faq-list></faq-list>两个指令嵌入到首页。注意,我们在这里拆出这两个指令的直接目的不是为了复用,更重要的目的应该是分离View,促进代码结构的优化,达到更好的语义化和组件化,当然对于这样独立内聚的指令,有时我们还能意外地获得更好的复用性。组件型指令应该是满足封装的自治性、内聚性的,它不应该直接引用当前页面的DOM结构、数据等。如果存在需要的信息,则可以通过指令的属性传递或者利用后端服务接口来自我满足。如login-panel应该在其内部访问登录接口来实现自我的功能封装。它的Scope应该是独立的(isolated),不需要对父作用域的结构有任何依赖,否则一旦父作用域的结构发生改变,可能它也需要相应地变更,这种封装是很脆弱的。更好的封装应该是“高内聚低耦合”的,内聚是描述组件内部实现了它所应该包含的逻辑功能,耦合则描述它和外部组件之间应该是尽量少的相互依赖。组件型指令的写法通常是这样的:记住,对于组件型指令,更重要的是内容信息的展示,所以我们一般不涉及指令的link函数,而应该尽量地将业务逻辑放置在Controller中。组件化的开发方式以及组件化的复用,是我们在前端开发中一直追求的一个理想目标。从最初的iframe、jQuery UI、Extjs、jQuery easyui,我们一直在不懈地朝着组件化的方向前进。Angular首次在其框架中提出指令这种以HTML DSL方式进行语义化、组件化扩展的方式,就我们在这里描述的组件型指令。 ## 装饰器型指令 装饰器型指令主要用于添加行为和保持View和Model的同步,所以它不同于组件型指令,我们经常需要进行DOM操作。其restrict属性通常为A,也就是属性声明方式,这种方式更符合装饰器的语义:它并不是一个内容的主体,而是附加行为能力的连接器。同时,由于多个装饰器很可能被用于同一个指令,包括独立作用域指令,所以装饰器型指令通常不使用新作用域或独立作用域。如果要访问绑定属性,该怎么做呢?仍然看前面的例子<user-details name="test"details="details"on-update="updateIt(times)"></user-details>,假如不使用独立作用域,我们该如何获取这些属性的值呢?·对于@型的绑定,我们可以直接通过attrs取到它:attrs.name等价于name:'@'。·对于=型的绑定,我们可以通过scope.$eval取到它:scope.$eval(attrs.details)等价于details:'='。&型的绑定理解起来会稍有困难,先看代码:scope.$eval(attrs.onUpdate,{times:3});。和=型绑定一样,onUpdate属性在本质上是当前scope上的一个表达式。特殊的地方在于,这个表达式是一个函数,$eval发现它是函数时,就可以传一个参数表(在Angular中称之为locals)给它。onUpdate表达式中可以使用的参数名和它的参数值,都来自这个参数表。使用的时候,我们可以在视图中引用这个哈希对象的某个属性作为参数,在装饰器指令中,其实还有一种细分的分支,它完全不操纵DOM,只是对当前scope进行处理,如添加成员变量、函数等。