有关自定义指令的scope参数,网上不少文章都在讲这3种绑定方式实现的效果是什么,但几乎没有人讲到底怎么使用,本篇但愿聊聊到底怎么用这个话题。html
自定义指令,是Angularjs
用来实现组件化的方式,相比于React
和Vue
的组件化方式,它真的很复杂,自定义指令过重了,它暴露了太多可供定制的参数,以致于普通的开发者彻底不知道要用它来作什么而将其束之高阁,毕竟通常的业务逻辑经过controller和service就已经能够完成了。ajax
自定义指令在Angularjs
项目中主要有两大用途:数组
1.封装指定组件的DOM操做框架
Angularjs
指望的开发方式是将DOM的操做尽量封装在自定义指令中,这样对于局部变量的操做会更容易加入到Angular本身的生命周期中。ide
2.组件化函数
Angularjs
靠自定义指令实现组件化。诸如你在React
和Vue
中看到的相似于
Angularjs
中所有都是经过自定义指令来实现的。组件化
自定义指令在定义后,须要在html文件中编写,最经常使用的方式是将其书写为标签属性。当使用自定义指令时,经常须要将一个变量的值从controller传递至directive中,此时须要在scope
属性中进行变量绑定设置,Angularjs
提供了3种不一样的绑定方式(实际上也能够直接传递True),以下所示:设计
scope: { infiniteScroll: '=', // 将infiniteScroll同父级controller中的指定对象双向绑定 onSend: '&', // 从父级获取一个变量的引用,经常使用做方法调用 fromName: '@' // 从父级获取值后便只在本地做用域生效 }
关于三种绑定方式使用的方法,网上能够搜到很是多的文章,本篇再也不赘述,今天咱们只来详细看一下这几种方式的使用场景和区别。双向绑定
@绑定
能够转移常量赋值的位置,经常使用于为自定义封装组件暴露一个可设定常量参数的接口。这种绑定方式的意义,在于从自定义指令外部(通常是从html页面上绑定一个常量或控制器中的变量)获取一个局部变量的值。code
实际场景:
例如咱们封装了一个分页组件,其中指令局部做用域中的displayPaginationNums
属性用于决定分页组件的页码栏显示多少个按钮,而后把剩余的按钮收起来并添加...
按钮,这是一个很常见的需求。
不使用@绑定
不使用@绑定,彻底能够作到,只须要在link函数里,初始化为其赋值便可。
link:function(scope, elements, attrs){ scope.displayPaginationNums = 5;//用于决定分页导航栏最多可显示几个数字 },
使用这样的方式,就能够,但咱们默认了一个前提,那就是全部调用这个组件的人,都会浏览这个组件的源代码。这实际上是很不方便的,换位思考一下,你使用Angularjs
的时候,会先去源码里找一下对应的方法开头都定义了哪些变量,哪些能够修改吗?固然不会。
这个属性在不一样的项目中都会须要赋值,但须要动态去修改的场景其实并很少,因此咱们须要将接口暴露至更高的开发层级,供调用者直接赋值。
使用@绑定
当使用@绑定后,咱们其实是面向调用者暴露了去设定重要参数的接口,使用起来更加方便。下面的写法让开发者使用这个组件时,能够在代码编写时方便地传入本身想要设定的值:
//指令定义时 scope:{ displayPaginationNums:'@' },
<!--指令调用时--> <div table-pagination display-pagination-nums="5">
面向对象程序设计原则中有一个重要的原则,叫作开放封闭原则,它的意思是说,你在程序设计中所书写的代码,应该对扩展开放,对修改封闭。简单地说就是你所编写的代码成型之后,在后续的使用和功能扩展的时候,尽量不须要再去改动代码,而只须要经过编写与扩展相关的代码便可。
此处就是从封闭转为开放的一个示例,虽然看起来很细小,但能够很明确地表达这个原则。
&绑定
用于传递父级函数的引用,用来调用父级控制器中定义的方法。若是只是以业务逻辑为模块进行封装,这种绑定方式能够帮咱们避免一部分代码重复,若是是为通用框架编写纯组件,则能够为调用者提供自定义函数的接口。
实际场景:
好比咱们在制做一个表格和分页组件时,表格每一页只显示10条数据,分页是后台来完成的,那么每一次点击分页组件上的页码按钮时,咱们都须要向后台发送ajax请求来获取新一页的数据。那么这个发送ajax请求的方法你会写在哪里呢?
不使用&绑定
将方法写在controller中
优点:这样作的好处是若是之后咱们须要增长一个输入框来实现精确跳转到哪一页时,能够直接在模板中使用ng-change="sendAjax( )"
来绑定这个方法,方便复用,扩展,甚至修改功能。
劣势:但这样作的话,若是想在自定义指令中就没法直接调用这个方法,常见的处理策略是在自定义指令中使用scope.$emit( )
将一个自定义事件发送至父级controller,在父级controller中使用$scope.$on( )
来监听这个自定义事件,并在回调中执行$scope.sendAjax( )
这个方法。
将方法写在指令的link函数中
优点:能够将一些不须要用户感知的函数封装起来,例如数据发送前的校验,或是响应数据的结构重组等,提升业务逻辑相关的代码在controller中的比重,减少controller的体积。
劣势:当其余组件想要使用这个方法时会很困难,Angularjs并无提供一种跨directive调用方法的机制。
实际上在开发过程当中,不熟悉&绑定
的开发者在使用自定义指令时,几乎都会选择将方法写在controller中并经过消息机制来触发这个函数(也就是上文中第一个方法),他们但愿指令所封装的组件是纯粹的,换句话说,它是可复用且与业务逻辑剥离的。
使用&绑定
对于业务逻辑开发而言
简洁且容易使用,组件可直接调用controller中的业务逻辑代码,避免了当自定义事件过多时形成的controller中充满了事件监听的回调方法的问题,使用方法以下:
//主模板中 <div change-page="sendAjax"></div>
//指令定义中 ... template:'<div ng-click="changePage()"></div>' scope:{ changePage: '&' }, ...
对于模块封装而言
从上面的示例就能够看出,自定义指令中实际执行的changePage( )
方法,是用户在使用这个组件时编写在controller之中的sendAjax( )这个方法,当咱们须要封装一个供其余开发者调用的组件时(每每是在编写一个组件库),这种结构是在angular中最天然的实现方式。
当你但愿给一个自定义指令暴露愈来愈多个性化定制接口时,它极可能变得臃肿,甚至一无可取。
&绑定
意义,在于将业务逻辑从组件中剥离出来,但过多的可定制性又会给开发者带来额外的问题,你会发现,仅仅是简单地使用一个下拉框或是勾选框之类的简单组件时,就须要传入一大堆自定属性,而这本该是在交互设计标准中肯定好并编写在项目中的指定位置的。自定义指令的可定制性越高,html模板的体积就会越大,controller中的代码量也会随之增大,带来的直接问题就是:开发很方便,维护很痛苦。
=绑定
是3中绑定形式中最经常使用的一种,经常使用于将用于渲染的数组或对象传入自定义指令中。这样作能够将业务逻辑分块,使得代码结构更具备层次性,下降维护难度。
实际场景:
一个表格组件,须要经过ajax请求从后台获取100条用于展现的数据,这些数据可能须要排序,过滤,分页等操做,首先应该明确的是,即时这些代码所有写在controller中,程序也是能够运行的,只是当你在其余场合须要复用时,就须要复制粘贴不少代码。那么该如何来设计这样一个功能并提取公用组件呢?排序
,过滤
,分页
都是表格组件的通用动做,也就是说与数据对象自己的结构并无太大关系,对于一个通用型表格控件来讲,咱们惟一必需要传入的只有一项——数据源,且它是有可能会随着用户操做而发生变化的。
推荐的技术方案为:
这样的结构,使宏观业务逻辑,先后台信息交互,组件通用功能分别在不一样的模块中实现,能够极大提升定位问题的速度。
=绑定
的双向数据绑定在使用中是存在一些方法问题的,详情请参考《Angularjs1.X进阶笔记(1)—两种不一样的双向数据绑定》
。
=绑定
—— 经常使用于传递从后台获取的用于驱动纯组件的源数据。
@绑定
—— 为自定义指令中传递可配置的常量参数提供设置接口。
&绑定
—— 为自定义指令中传递自定义方法提供接口。