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

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

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

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

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

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

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

(0)

相关推荐

  • Angularjs中数据绑定的实例详解

    Angularjs中数据绑定的实例详解 这是一个最简单的angularjs的例子,关于数据绑定的,大家可以执行一下,看看效果 <html ng-app> <head> <title>angularjs-include</title> <script type="text/javascript" src="js/angular/angular.min.js"></script> </head

  • Angular数据绑定机制原理

    1.Angular.js扩展浏览器的事件循环 浏览器持续等待例如用户交互这样的事件.当你在一个<input>标签里输入字符之后,这个事件的回调函数在JS解释器中执行了其包含的DOM操作,执行完毕后,浏览器响应地对DOM做出了变化.Angular拓展了这个事件循环,使它有时候成为angular context 的执行环境. 2.$watch list $watch 可以检测model的变化.每当绑定一个数据到view上的时候,$watch队列就会插入一条对应的$watch.例子如下: contr

  • 浅谈Angularjs中不同类型的双向数据绑定

    Angularjs1.X中两种不同的双向数据绑定 聊聊 Angularjs1.x中那些活见鬼的事情. 一. html与Controller中的双向数据绑定 html-Controller的双向数据绑定,在开发中非常常见,也是Angularjs1.x的宣传点之一,使用中并没有太多问题. 1.1数据从html流向controller 也就是从 视图层 流向 模型层 ,原生html中需要使用表单元素(例如 input 标签)来收集用户输入信息,Angularjs中通过在表单元素上使用 ng-model

  • Angular2学习笔记之数据绑定的示例代码

    简介 使用插值表达式将一个表达式的值显示在模版上 <img src="{{imgUrl}}" alt=""> <h1>{{productTitle}}</h1> 使用方括号将HTML标签的一个属性值绑定到一个表达式上 <img [src]="imgUrl" alt=""> 使用小括号将组件控制器的一个方法绑定到模版上面的一个事件的处理器上 <button (click)=&

  • AngularJS双向数据绑定原理之$watch、$apply和$digest的应用

    引子 这篇文章是写给AngularJS新手的,如果你已经对AngularJS的双向数据绑定有了深入的了解,直接去阅读源代码好了. 背景 AngularJS开发者都想知道双向数据绑定是怎么实现的.与data-binding相关的术语琳琅满目: $watch,$apply,$digest,dirty-checking等等它们是如何工作的呢?让我们从头开始讲起吧 AngularJS 的双向数据绑定是被浏览器逼的 浏览器看上去很美,其实在数据交互这块儿,由于浏览器的"不作为",导致浏览器的数据

  • 浅谈AngularJs 双向绑定原理(数据绑定机制)

    那么什么是双向绑定,下面简单进行讲解. 首先我们要理解数据绑定.我们看到的网站页面中,是由数据和设计两部分组合而成.将设计转换成浏览器能理解的语言,便是html和css主要做的工作.而将数据显示在页面上,并且有一定的交互效果(比如点击等用户操作及对应的页面反应)则是js主要完成的工作.很多时候我们不可能每次更新数据便刷新页面(get请求),而是通过向后端请求相关数据,并通过无刷新加载的方式进行更新页面(post请求).那么数据进行更新后,页面上相应的位置也能自动做出对应的修改,便是数据绑定. 在

  • Angular自定义组件实现数据双向数据绑定的实例

    学过Angular的同学都知道,输入框通过[(ngModel)]实现双向数据绑定,那么自定义组件能不能实现双向数据绑定呢?答案是肯定的. Angular中,我们常常需要通过方括号[]和圆括号()实现组件间的交互: 那么在[]和()的基础上,如何实现组件的双向数据绑定? 例子如下. 子组件: <!--testDataBinding.component.html--> <h1>childStatus: {{childStatus}}</h1> //testDataBindi

  • angularjs 的数据绑定实现原理

    在angularjs1.X 中存在了三种数据绑定的方式,用于数据的同步.展示.在 angularjs 1.3 之前,angularjs 只存在两种方式: two-way-binding 和 one-way-bindng , 而后则引入了称为one-time-binding 的绑定机制. 目前angularjs 中存在以下三种数据绑定方式: two-way-binding one-way-binding one-time-binding two-way-binding angularjs 中的 T

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

    有关自定义指令的scope参数,网上很多文章都在讲这3种绑定方式实现的效果是什么,但几乎没有人讲到底怎么使用,本篇希望聊聊 到底怎么用 这个话题. 一. 自定义指令 自定义指令,是 Angularjs 用来实现组件化的方式,相比于 React 和 Vue 的组件化方式,它真的很复杂,自定义指令太重了,它暴露了太多可供定制的参数,以至于普通的开发者完全不知道要用它来做什么而将其束之高阁,毕竟一般的业务逻辑通过controller和service就已经可以完成了. 自定义指令在 Angularjs

  • 详解angularJS自定义指令间的相互交互

    AngularJS 自定义指令 transclude:当元素标签需要嵌套时使用,与ng-transclude配合使用.默认值为false不能使用嵌套,true为可以使用嵌套.在哪个标签上使用ng-transclude就在哪个标签内进行嵌套. 代码示例:(将hello.hi标签进行替换同时span标签嵌套div内) <script type="text/javascript"> var m = angular.module('myApp',[]); m.directive('

  • 详解Vue自定义指令及使用

    一.什么是指令 学习 vue 的时候肯定会接触指令,那么什么是指令呢? 在 vue 中提供了一些对于页面和数据更为方便的输出,这些操作就叫做指令,以 v-xxx 表示,比如 html 页面中的属性 <div v-xxx ></div> 比如在 angular 中 以 ng-xxx 开头的就叫做指令 指令中封装了一些 DOM 行为,结合属性作为一个暗号,暗号有对应的值,根据不同的值,会进行相关 DOM 操作的绑定,即可以进行一些模板的操作 vue 中常用的一些内置 v- 指令 v-t

  • 详解Angular.js指令中scope类型的几种特殊情况

    前言 大家都知道在默认情况下,指令应该访问父作用域.如果我们对指令暴露了父控制器的scope,那么指令就可以自由的修改scope属性.在一些情况下,你的指令可能想要添加一些只有内部可以使用的属性和函数,如果我们都在父作用域中完成,可能会污染了父作用域,因此,我们有以下两种选择: 使用父作用域-如果不需要操作父作用域属性,不需要一个新的作用域,可以直接使用父作用域 scope:false 一个子作用域-这个作用域会原型继承父作用域 scope:true 一个隔离的作用域-一个全新的.不继承.独立存

  • 详解AngularJS中自定义指令的使用

    自定义指令中使用AngularJS扩展HTML的功能.自定义指令使用的"指令"的功能定义.自定义指令只是替换了它被激活的元素.引导过程中AngularJS应用程序找到了匹配的元素,并做好使用自定义指令compile()方法一次活动再处理使用基于指令的范围自定义指令link()方法的元素. AngularJS提供支持,以下列元素的类型来创建自定义指令. Element directives - 指令遇到时激活一个匹配的元素. Attribute - - 指令遇到时激活一个匹配的属性. C

  • AngularJS自定义指令详解(有分页插件代码)

    前言 除了 AngularJS 内置的指令外,我们还可以创建自定义指令. 通过 .directive() 函数来添加自定义的指令. 调用自定义指令时,需要在HTMl 元素上添加自定义指令名. 自定义指令命名规则:使用驼峰命名法来命名,即除第一个单词外的首字母需大写.如: myDirective. 在html页面调用该指令时需要以 - 分割,如: my-directive.示例代码: <body ng-app="myApp"> <my-directive><

  • 详解AngularJS中$filter过滤器使用(自定义过滤器)

    1.内置过滤器 * $filter 过滤器,是angularJs中用来处理数据以更好的方式展示给我用户.比如格式化日期,转换大小写等等. * 过滤器即有内置过滤器也支持自定义过滤器.内置过滤器很多,可以百度.关键是如何使用: * 1.在HTML中直接使用内置过滤器 * 2.在js代码中使用内置过滤器 * 3.自定义过滤器 * * (1)常用内置过滤器 * number 数字过滤器,可以设置保留数字小数点后几位等 * date 时间格式化过滤器,可自己设置时间格式 * filter 过滤的数据一般

  • AngularJS 自定义指令详解及实例代码

    AngularJS支持用户自定义标签属性,在不需要使用DOM节点操作的情况下,添加自定义的内容. 前面提到AngularJS的四大特性: 1 MVC 2 模块化 3 指令 4 双向数据绑定 下面将会介绍如下的内容: 1 如何自定义指令 2 自定义指令的使用 3 自定义指令的内嵌使用 如何自定义指令: Angular是基于模块的框架,因此上来肯定要创建一个自己的模块: var myAppModule = angular.module("myApp",[]); 然后在此模块基础上创建指令d

  • Angularjs自定义指令Directive详解

    今天学习angularjs自定义指令Directive. Directive是一个非常棒的功能.可以实现我们自义的的功能方法. 下面的例子是演示用户在文本框输入的帐号是否为管理员的帐号"Admin". 在网页上放一个文本框和一个铵钮: <form id="form1" name="form1" ng-app="app" ng-controller="ctrl" novalidate> <i

  • AngularJS  自定义指令详解及实例代码

    AngularJS支持用户自定义标签属性,在不需要使用DOM节点操作的情况下,添加自定义的内容. 前面提到AngularJS的四大特性: 1 MVC 2 模块化 3 指令 4 双向数据绑定 下面将会介绍如下的内容: 1 如何自定义指令 2 自定义指令的使用 3 自定义指令的内嵌使用 如何自定义指令: Angular是基于模块的框架,因此上来肯定要创建一个自己的模块: var myAppModule = angular.module("myApp",[]); 然后在此模块基础上创建指令d

随机推荐