Angularjs进阶笔记(2)-自定义指令中的数据绑定
有关自定义指令的scope参数,网上很多文章都在讲这3种绑定方式实现的效果是什么,但几乎没有人讲到底怎么使用,本篇希望聊聊到底怎么用这个话题。
一. 自定义指令
自定义指令,是Angularjs用来实现组件化的方式,相比于React和Vue的组件化方式,它真的很复杂,自定义指令太重了,它暴露了太多可供定制的参数,以至于普通的开发者完全不知道要用它来做什么而将其束之高阁,毕竟一般的业务逻辑通过controller和service就已经可以完成了。
自定义指令在Angularjs项目中主要有两大用途:
1.封装指定组件的DOM操作
Angularjs期望的开发方式是将DOM的操作尽可能封装在自定义指令中,这样对于局部变量的操作会更容易加入到Angular自己的生命周期中。2.组件化
Angularjs靠自定义指令实现组件化。诸如你在React和Vue中看到的类似于,这样的自定义标签,或是父级子级传值所使用的prop,又或者是标记组件自身状态的state,在Angularjs中全部都是通过自定义指令来实现的。
二. 数据绑定的形式
自定义指令在定义后,需要在html文件中编写,最常用的方式是将其书写为标签属性。当使用自定义指令时,常常需要将一个变量的值从controller传递至directive中,此时需要在scope属性中进行变量绑定设置,Angularjs提供了3种不同的绑定方式(实际上也可以直接传递True),如下所示:
scope: {
infiniteScroll: '=', // 将infiniteScroll同父级controller中的指定对象双向绑定
onSend: '&', // 从父级获取一个变量的引用,常用作方法调用
fromName: '@' // 从父级获取值后便只在本地作用域生效
}
关于三种绑定方式使用的方法,网上可以搜到非常多的文章,本篇不再赘述,今天我们只来详细看一下这几种方式的使用场景和区别。
2.1 @绑定
@绑定可以转移常量赋值的位置,常用于为自定义封装组件暴露一个可设定常量参数的接口。这种绑定方式的意义,在于从自定义指令外部(一般是从html页面上绑定一个常量或控制器中的变量)获取一个局部变量的值。
实际场景:
例如我们封装了一个分页组件,其中指令局部作用域中的displayPaginationNums属性用于决定分页组件的页码栏显示多少个按钮,然后把剩余的按钮收起来并添加...按钮,这是一个很常见的需求。
不使用@绑定
不使用@绑定,完全可以做到,只需要在link函数里,初始化为其赋值即可。
link:function(scope, elements, attrs){
scope.displayPaginationNums = 5;//用于决定分页导航栏最多可显示几个数字
},
使用这样的方式,就可以,但我们默认了一个前提,那就是所有调用这个组件的人,都会浏览这个组件的源代码。这其实是很不方便的,换位思考一下,你使用Angularjs的时候,会先去源码里找一下对应的方法开头都定义了哪些变量,哪些可以修改吗?当然不会。
这个属性在不同的项目中都会需要赋值,但需要动态去修改的场景其实并不多,所以我们需要将接口暴露至更高的开发层级,供调用者直接赋值。
使用@绑定
当使用@绑定后,我们实际上是面向调用者暴露了去设定重要参数的接口,使用起来更加方便。下面的写法让开发者使用这个组件时,可以在代码编写时方便地传入自己想要设定的值:
//指令定义时
scope:{
displayPaginationNums:'@'
},
<!--指令调用时-->
<div table-pagination
display-pagination-nums="5">
面向对象程序设计原则中有一个重要的原则,叫做开放封闭原则,它的意思是说,你在程序设计中所书写的代码,应该对扩展开放,对修改封闭。简单地说就是你所编写的代码成型以后,在后续的使用和功能扩展的时候,尽可能不需要再去改动代码,而只需要通过编写与扩展相关的代码即可。
此处就是从封闭转为开放的一个示例,虽然看起来很细小,但可以很明确地表达这个原则。
2.2 &绑定
&绑定用于传递父级函数的引用,用来调用父级控制器中定义的方法。如果只是以业务逻辑为模块进行封装,这种绑定方式可以帮我们避免一部分代码重复,如果是为通用框架编写纯组件,则可以为调用者提供自定义函数的接口。
实际场景:
比如我们在制作一个表格和分页组件时,表格每一页只显示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中的代码量也会随之增大,带来的直接问题就是:开发很方便,维护很痛苦。
2.3 =绑定
=绑定是3中绑定形式中最常用的一种,常用于将用于渲染的数组或对象传入自定义指令中。这样做可以将业务逻辑分块,使得代码结构更具有层次性,降低维护难度。
实际场景:
一个表格组件,需要通过ajax请求从后台获取100条用于展示的数据,这些数据可能需要排序,过滤,分页等操作,首先应该明确的是,即时这些代码全部写在controller中,程序也是可以运行的,只是当你在其他场合需要复用时,就需要复制粘贴很多代码。那么该如何来设计这样一个功能并提取公用组件呢?排序,过滤,分页都是表格组件的通用动作,也就是说与数据对象本身的结构并没有太大关系,对于一个通用型表格控件来说,我们唯一必须要传入的只有一项——数据源,且它是有可能会随着用户操作而发生变化的。
推荐的技术方案为:
- service : 封装$http操作,信息提示,及容错处理
- controller : 调用service暴露的方法从后台获取数据,并赋值给指定变量
- directive : 双向数据绑定controller中的变量以获取驱动表格渲染的数据,将排序,过滤,分页的具体实现封装在指令内部。
这样的结构,使宏观业务逻辑,前后台信息交互,组件通用功能分别在不同的模块中实现,可以极大提高定位问题的速度。
=绑定的双向数据绑定在使用中是存在一些方法问题的,详情请参考《Angularjs1.X进阶笔记(1)—两种不同的双向数据绑定》。
三. 自定义指令的实用意义
=绑定—— 常用于传递从后台获取的用于驱动纯组件的源数据。@绑定—— 为自定义指令中传递可配置的常量参数提供设置接口。&绑定—— 为自定义指令中传递自定义方法提供接口。
Angularjs进阶笔记(2)-自定义指令中的数据绑定的更多相关文章
- AngularJs学习笔记3——自定义指令
指令 概述: 前面也说过一些常用指令,用于快速入门.现在详细总结一下:指令用于实现各种页面的操作,是对于底层DOM操作的封装,扩展了HTML的行为,实现页面交互以及数据绑定. 指令是一种执行的信号,一 ...
- AngularJS学习笔记(四) 自定义指令
指令(directive)是啥?简单来说就是实现一定功能的XXX...之前一直用的ng-model,ng-click等等都是指令.当我有一个ng没提供的需求的时候,就可以自定义个指令.指令的好处显而易 ...
- Angular6在自定义指令中使用@HostBingDing() 和@HostListener()
emmm,,,最近在为项目的第二阶段铺路,偶然看到directive,想想看因为项目已经高度集成了第三方组件,所以对于自定义指令方面的经验自己实在知之甚少,后面经过阅读相关资料,总结一篇关于在自定义指 ...
- AngularJS:如何使用自定义指令来取代ng-repeat
引言 本文主要介绍了另一种即具有与ng-repeat 一样处理大量数据的绑定的功能,又具有超高的性能. 对于处理小数量,ng-repeat是非常有用的,但是如果需要处理非常大的数量集,还是采用自定义的 ...
- 【AngularJS学习笔记】01 指令、服务和过滤器
AngularJS 指令是扩展的 HTML 属性,带有前缀 ng-. 比如: ng-app 指令初始化一个 AngularJS 应用程序.注意ng-app一般为空,如果值不为空,就得加这样一句代码va ...
- AngularJs学习笔记5——自定义服务
前面整理了AngularJs双向数据绑定和自定义指令的相关内容,从手册上看也知道,ng部分还包括过滤器和函数,以及服务等. 过滤器:filter,就是对数据进行格式化,注意管道格式,例如: {{表达式 ...
- angularJS1笔记-(11)-自定义指令(transclude/priority/terminal)
自定义指令的属性 transclude:为true时,允许把html中新定义的指令中原来的dom运用到该指令的template中. 属性priority,设置该指令的优先级,优先级大的先执行,默认指令 ...
- Vue笔记--通过自定义指令实现按钮操作权限
经常做中后台系统,此类系统的权限是比较重要,拿自己做过的一些项目做个笔记. Vue实现的中后台管理系统.按钮操作权限的空置一般都是通过自定义指令Vue.directive. <el-button ...
- angularJS1笔记-(14)-自定义指令(scope)
index.html: <!DOCTYPE html> <html lang="en"> <head> <meta charset=&qu ...
随机推荐
- Kafka监控工具kafka-monitor v0.1简要介绍
Kafka Monitor为Kafka的可视化管理与监控工具,为Kafka的稳定运维提供高效.可靠.稳定的保障,这里主要简单介绍Kafka Monitor的相关功能与页面的介绍: Kafka Moni ...
- ORACLE启动报错ORA-03113: end-of-file on communication channel
使用过程中发现oracle运行很慢(其实应该先关注空间问题),就准备关机重启一下,关不掉就强制关闭,然后启动就报错了. 1.SQL> startup ORACLE instance starte ...
- socketserver模块TCP和UDP协议形式
# >>>>>>>>>>>>>>>>>>>>服务端socketserver模块通 ...
- nginx 静态目录配置规则
1.子目录匹配 如下配置 location / { root /data/www; } 访问http://127.0.0.1/时,配匹配/data/www 访问http://127.0.0.1/ima ...
- 邮件服务器 postfix
背景介绍 邮件服务器普遍需要一个主机名来使得mail from 以"账号@主机名"方式显示.由于外网上垃圾邮件太多,现在已不使用ip发邮件,很多网络供应商都会对来源不明的邮件进行限 ...
- 关于如何在Visual Studio上仿真调试安卓的U3D应用
正巧最近需要开发一个安卓手机上的Unity3D游戏功能,想着既然要开发么,当然需要调试.本来的话一些基础功能是不需要使用仿真模拟器,直接在U3D的开发编辑器上就能调试,不过有一些安卓上才能执行,比如 ...
- Linux下不同文件不同颜色的意义
通常,我们使用ls查看文件时,会出现不同颜色的文件,今天我就大概写一下不同颜色的代表意义: 蓝色————目录: 绿色————可执行文件: 红色————压缩文件: 浅蓝色————链接文件: 紫红色——— ...
- 使用Kubeadm(1.13+)快速搭建Kubernetes集群
Kubeadm是管理集群生命周期的重要工具,从创建到配置再到升级,Kubeadm处理现有硬件上的生产集群的引导,并以最佳实践方式配置核心Kubernetes组件,以便为新节点提供安全而简单的连接流程并 ...
- 让一个数组中存在N多个函数。让每个函数执行的 时候自动加1
function test(){ var arr = [ ]; for (var i = 0; i < 10; i++) { (function(i){ arr[i] = function(){ ...
- python之Django学习笔记(三)---URL调度/URL路由
在django中,用户发起url请求消息首先到工程的urls.py中查找是否有匹配的url路径 刚创建好的工程中urls.py只有下面几行代码: from django.contrib import ...