详解Angularjs 自定义指令中的数据绑定


Posted in Javascript onJuly 19, 2018

有关自定义指令的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)—两种不同的双向数据绑定》

三. 自定义指令的实用意义

=绑定 —— 常用于传递从后台获取的用于驱动纯组件的源数据。

@绑定 —— 为自定义指令中传递可配置的常量参数提供设置接口。

&绑定 —— 为自定义指令中传递自定义方法提供接口。

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

Javascript 相关文章推荐
pjblog修改技巧汇总
Mar 12 Javascript
javascript一点特殊用法
May 28 Javascript
js兼容标准的表格变色效果
Jun 28 Javascript
如何将php数组或者对象传递给javascript
Mar 20 Javascript
jQuery scroll事件实现监控滚动条分页示例
Apr 04 Javascript
jQuery遍历之next()、nextAll()方法使用实例
Nov 08 Javascript
js仿苹果iwatch外观的计时器代码分享
Aug 26 Javascript
Node.js实用代码段之正确拼接Buffer
Mar 17 Javascript
WebSocket+node.js创建即时通信的Web聊天服务器
Aug 08 Javascript
微信小程序实现顶部普通选项卡效果(非swiper)
Jun 19 Javascript
微信小程序中button去除默认的边框实例代码
Aug 01 Javascript
Vue自定义铃声提示音组件的实现
Jan 22 Vue.js
微信小程序实现天气预报功能
Jul 18 #Javascript
vue代理和跨域问题的解决
Jul 18 #Javascript
小程序自定义组件实现城市选择功能
Jul 18 #Javascript
微信小程序实践之动态控制组件的显示/隐藏功能
Jul 18 #Javascript
微信小程序项目实践之主页tab选项实现
Jul 18 #Javascript
详解性能更优越的小程序图片懒加载方式
Jul 18 #Javascript
微信小程序项目实践之验证码倒计时功能
Jul 18 #Javascript
You might like
ThinkPHP的I方法使用详解
2014/06/18 PHP
PHP获取数组长度或某个值出现次数的方法
2015/02/11 PHP
windows下安装php的memcache模块的方法
2015/04/07 PHP
Yii实现Command任务处理的方法详解
2016/07/14 PHP
php 反斜杠处理函数addslashes()和stripslashes()实例详解
2016/12/25 PHP
thinkphp3.2.0 setInc方法 源码全面解析
2018/01/29 PHP
PHP文件上传小程序 适合初学者学习!
2019/05/23 PHP
读jQuery之十 事件模块概述
2011/06/27 Javascript
Jquery异步请求数据实例代码
2011/12/28 Javascript
js中的前绑定和后绑定详解
2013/08/01 Javascript
输入自动提示搜索提示功能的使用说明:sugggestion.txt
2013/09/02 Javascript
DOM节点的替换或修改函数replaceChild()用法实例
2015/01/12 Javascript
jquery事件的ready()方法使用详解
2015/11/11 Javascript
JavaScript如何动态创建table表格
2020/08/02 Javascript
实例详解jQuery的无new构建
2016/08/02 Javascript
HTML页面,测试JS对C函数的调用简单实例
2016/08/09 Javascript
JavaScript中Number对象的toFixed() 方法详解
2016/09/02 Javascript
微信小程序 配置文件详细介绍
2016/12/14 Javascript
用户管理的设计_jquery的ajax实现二级联动效果
2017/07/13 jQuery
仿ElementUI实现一个Form表单的实现代码
2019/04/23 Javascript
微信小程序批量上传图片到七牛(推荐)
2019/12/19 Javascript
python opencv 批量改变图片的尺寸大小的方法
2019/06/28 Python
Python动态导入模块:__import__、importlib、动态导入的使用场景实例分析
2020/03/30 Python
使用Pycharm(Python工具)新建项目及创建Python文件的教程
2020/04/26 Python
利用CSS3实现折角效果实例源码
2016/09/28 HTML / CSS
分享29个基于Bootstrap的HTML5响应式网页设计模板
2015/11/19 HTML / CSS
四种会话跟踪技术
2015/05/20 面试题
高中数学教师求职信
2013/10/30 职场文书
上班离岗检讨书
2014/01/27 职场文书
分层教学实施方案
2014/03/19 职场文书
工程学毕业生自荐信
2014/06/14 职场文书
学生自我鉴定格式及范文
2014/09/16 职场文书
走群众路线学习心得体会
2014/10/31 职场文书
python中sys模块的介绍与实例
2021/04/17 Python
Kubernetes关键组件与结构组成介绍
2022/03/31 Servers
PostgreSQL聚合函数介绍以及分组和排序
2022/04/12 PostgreSQL