创建可复用组件实例代码

本文不仅会介绍Directive的一般创建过程,与DOM相关的逻辑都应该包含在其他的指令中

AngularJS框架能够用Service和Directive减弱开辟复杂性。那些天性特别适合用于分离代码,创设可测量检验组件,然后将它们成为可选取组件。

前言

Directive是一组独立的JavaScript、HTML和CSS,它们封装了一个特定的行为,它将成为现在开创的Web组件的组成都部队分,大家得以在各样应用中收音和录音这么些零部件。在成立之后,大家得以平素通过二个HTML标签、自定义属性或CSS类、以至能够是HTML注释,来进行二个Directive。

在Angular应用中,ng-model指令时不可缺点和失误的七个局地,它用来将视图绑定到多少,是双向绑定法力中首要的一环。ngModelController则是ng-model指令中所定义的controller。那些controller包蕴了有个别用以数据绑定,验证,CSS更新,以及数值格式化和深入分析的劳动。它不用来扩充DOM渲染只怕监听DOM事件。与DOM相关的逻辑都应有包涵在别的的下令中,然后让这个指令来试用ngModelController中的数据绑定功效。

这一篇教程将介绍怎么着创造一个‘自定义步长选用’
Directive,它能够用作二个可采纳输入组件。本文不仅仅会介绍Directive的一般制造进程,还可能会介绍输入控件验证办法,以及怎么着行使ngModelController无缝整合大肆表单,从而选用AngularJS表单的幸存庞大功效。

注意:本篇小说不是对NgModelController文书档案的认证,而是更偏侧施行。下边笔者将全程携带大家去落到实处多少个自定义指令,况兼使用ng-model属性来做双方的数量绑定。

直接上代码:

示例

html:

咱俩的app中选拔了三个自定义的一声令下,名字叫做timeDruation

<!-- lang: html -->
<body ng-app="demo" ng-controller="DemoController">
  <form name="form" >
    Model value : <input type="text" size="3" ng-model="rating"><br>
    Min value: <input type="text" size="3" ng-model="minRating"><br>
    Max value: <input type="text" size="3"ng-model="maxRating"><br>
    Form has been modified : {{ form.$dirty }}<br>
    Form is valid : {{ form.$valid }}
    <hr><divmin="minRating"max="maxRating"ng-model="rating"rn-stepper></div></form></body>

如下

js:

<div ng-app="HelloApp" ng-controller="HelloController">
 <h1>自定义指令</h1>
 <time-duration ng-model="test"></time-duration>
 <h1> 默认指令</h1>
 <input ng-model="test">second
</div>
<!-- lang: js -->
angular.module(‘demo‘, [
  ‘revolunet.stepper‘
])

.controller(‘DemoController‘, function($scope) {
  $scope.rating = 42;   
  $scope.minRating = 40;
  $scope.maxRating = 50;
});

JS代码如下,

rn-stepper最简结构

angular.module('HelloApp', [])
 .directive('timeDuration', TimeDurationDirective);
 .controller('HelloController', function($scope) {
 $scope.test = 1;
 });
<!-- lang: js -->
// we declare a module name for our projet, and its dependencies (none)
angular.module(‘revolunet.stepper‘, [])
// declare our naïve directive
.directive(‘rnStepper‘, function() {
  return {
    // can be used as attribute or element
    restrict: ‘AE‘,
    // which markup this directive generates
    template: ‘<button>-</button>‘ +
            ‘<div>0</div>‘ +
            ‘<button>+</button>‘
  };
});

咱俩的演示指令能够做这么一件事,能够钦赐多少个周围的日子单位,並且能够输入数据。最后大家将获取相应的秒数。其成效的截图如下,

方今directive rnStepper 已经有了贰个简短的雏形了。

图片 1

能够有如下三种试用方法:

创建可复用组件实例代码。此地大家特意将test变量分别绑定到大家的自定义指令和私下认可指令中,以观望其效力。

<div rn-stepper> </div>
<rn-stepper> </rn-stepper>

自定义指令创建可复用组件实例代码。

demo:

闲谈少叙,上边来看代码

丰裕之中动作

创建可复用组件实例代码。创建可复用组件实例代码。先上指令的模板。从上海体育场合中得以看出,指令包括二个输入框二个下拉挑选框。

平昔上代码:

<div class="time-duration">
 <input ng-model='num'>
 <select ng-model='unit'>
 <option value="seconds">Seconds</option>
 <option value="minutes">Minutes</option>
 <option value="hours">Hours</option>
 <option value="days">Days</option>
 </select>
</div>
<!-- lang: js -->
.directive(‘rnStepper‘, function() {
  return {
    restrict: ‘AE‘,

    // declare the directive scope as private (and empty)
    scope: {},

    // add behaviour to our buttons and use a variable value
    template:
        ‘<button ng-click="decrement()">-</button>‘ +
        ‘<div>{{value}}</div>‘ +
        ‘<button ng-click="increment()">+</button>‘,

    // this function is called on each rn-stepper instance initialisation
    // we just declare what we need in the above template
    link: function(scope, iElement, iAttrs) {
      scope.value = 0;
      scope.increment = function() {
        scope.value++;
      };
      scope.decrement = function() {
        scope.value--;
      };
    }
  };
});

模板其实很简短,这里就比比较少说了。上边大家来看看那个命令的逻辑部分。

我们在template中,分别给七个button加多了click事件响应,在link方法中落到实处了响应的章程。
创建可复用组件实例代码。这里的scope是二个private scope,其成效域只限rnStepper那一个directive。

function TimeDurationDirective() {
 var tpl = '....'; // 指令模板代码就是上面的内容,这里就不复制了。

 return {
 restrict: 'E',
 replace: true,
 template: tpl,
 require: 'ngModel',
 scope: {},
 link: function(scope, element, attrs, ngModelController) {
  var multiplierMap = {
  seconds: 1,
  minutes: 60,
  hours: 3600,
  days: 86400
  };
  var multiplierTypes = ['seconds', 'minutes', 'hours', 'days'];

  // TODO
 }
 };
}

demo:

一声令下的link方法大家一时半刻TODO了它。前面会逐步健全。

与表面世界(外界功能域)的互动

自身先来探视那个命令的定义,当中使用了require表明。简单来说,require的功效便是为那个directive声澳优(Ausnutria Hyproca)个依附关系,表明此directive正视另三个限令的controller属性。

结束上边结束,大家的rnStepper都以友好跟自个儿玩,并未跟外界功用域举香港行政局地相互。

此地稍微说Bellamy下require的衍生用法。

创建可复用组件实例代码。下边大家将丰裕一个数目绑定,使rnStepper与外表世界创建联系。

创建可复用组件实例代码。我们能够在require前增加修辞量词,比如,

一向上代码:

return {
 require: '^ngModel'
}

return {
 require: '?ngModel'
}

return {
 require: '?^ngModel'
}
<!-- lang: js -->
scope: {
  value: ‘=ngModel‘
}

    
1、^前缀修饰表示同意查找当前命令的父级指令,假如找不到相应指令的controller则抛出三个错误。

咱俩在scope中增添了一组键值对,那样,会活动创设内部变量value与外界属性ngModel的沟通。
这里的=代表的野趣是双向绑定(double data-binding)。

    
2、?则意味着将以此require动作形成叁个可采用,意思便是找不到相应指令的controller固然了,不会抛出错误。

何以叫双向绑定?

     3、当然,大家也足以一同利用那四个前缀修饰。

即: 当value发生改造,那么ngModel也会产生退换,反之亦然。

周旋?ngModel,^ngModel大家接纳的频率要越来越高级中学一年级点。

在我们的这么些demo中,看上边这行代码:

比如

<!– lang: js –>
<div rn-stepper ng-model=”rating”></div>

<my-directive ng-model="my-model">
 <other-directive></other-directive>
</my-directive>

那边的意味就是: directive
rnStepper的内部变量value与外部scope中的rating建构了双向数据绑定。

这时,我们在other-directive中使用require: ^ngModel,它将会自行检索my-directive指令表明中的controller属性。

demo:

使用NgModelController

让大家组件越发团结

当大家证明了require: 'ngModel'从此,在link方法中会注入第多个参数,那个参数正是大家require的可怜指令对应的controller。这里就是停放指令ngModel的指控器ngModeController了。

一贯上代码:

link: function (scope, element, attrs, ngModelCtrl) {
 // TODO
}
<!-- lang: js -->
.directive(‘rnStepper‘, function() {
  return {
    // restrict and template attributes are the same as before.
    // we don‘t need anymore to bind the value to the external ngModel
    // as we require its controller and thus can access it directly
    scope: {},
    // the ‘require‘ property says we need a ngModel attribute in the declaration.
    // this require makes a 4th argument available in the link function below
    require: ‘ngModel‘,
    // the ngModelController attribute is an instance of an ngModelController
    // for our current ngModel.
    // if we had required multiple directives in the require attribute, this 4th
    // argument would give us an array of controllers.
    link: function(scope, iElement, iAttrs, ngModelController) {
      // we can now use our ngModelController builtin methods
      // that do the heavy-lifting for us

      // when model change, update our view (just update the div content)
      ngModelController.$render = function() {
        iElement.find(‘div‘).text(ngModelController.$viewValue);
      };

      // update the model then the view
      function updateModel(offset) {
        // call $parsers pipeline then update $modelValue
        ngModelController.$setViewValue(ngModelController.$viewValue + offset);
        // update the local view
        ngModelController.$render();
      }

      // update the value when user clicks the buttons
      scope.decrement = function() {
        updateModel(-1);
      };
      scope.increment = function() {
        updateModel(+1);
      };
    }
  };
});

$viewValue和$modelValue

此地,作者不在要求中间变量value了。因为大家在link方法中一度得到了ngModelController的引用,这里的ngModelController.$viewValue其实正是前方例子中的value。

在ngModelController中有三个很关键的品质,三个称为$viewValue,三个叫做$modeValue。

只是大家又增加了别的一组键值对require: ‘ngModel‘。

这两侧的意义官方的解说如下

咱俩选取了多少个新的API:

     $viewValue: Actual string value in the view.

ngModelController.$render:
在ngModel发生转移的时候框架自动调用,同步$modelValue和$viewValue,
即刷新页面。

     $modelValue: The value in the model, that the control is bound
to.

ngModelController.$setViewValue:
当$viewValue爆发改换时,通过此格局,同步更新$modelValue。
demo:

假设您对地方的官方表明有思疑的话,作者这里给出一种自身个人的分解。

谢谢阅读,希望能协理到大家,感激我们对本站的支撑!

$viewView便是指令渲染模板所用的值,而$modelView是在调整器中流通的值。相当多时候,那三个值恐怕是差异的。

您只怕感兴趣的稿子:

  • 详解Angular 4.x
    动态创造组件
  • Angular2学习课程之组件中的DOM操作详解
  • 详解angular2封装material2对话框组件
  • angular2倒计时组件使用详解
  • Angular
    2父亲和儿子组件数据传递之@ViewChild获取子组件详解
  • Angular2利用组件与指令完毕图片轮播组件
  • Angular
    2老爹和儿子组件数据传递之@Input和@Output详解(下)
  • Angular2开垦——组件规划篇
  • Angular2自定义分页组件
  • angular4自定义组件详解

譬喻说你在页面上展现了一个日子,它显得的或是是“Oct. 20
2016”那样的字符串,不过呢,这几个字符串在调整器中对应的值大概是叁个Javascript的Date对象的实例。

再比方说,大家的这么些time-duration示例中,$viewValue其实指的是命令模板中num和unit组合出来的值,而$modelValue是HelloAppController中test变量对应的值。

$formatters和$parses

除此而外$viewValue和$modelValue那七个天性之外,还会有五个用来管理他们的不二法门。分别是$parses和$formatters。

前端的是效能是将$viewValue->$modelValue,后面一个的效果与利益恰好相反,是将$modelValue->$viewValue

time-duration指令与表面调整器以及当中间的周转如下图,

图片 2

    
1、在表面调节器中(即这里的HelloApp的controller),大家通过ng-model="test"将test变量传入指令time-duration中,并树立绑定关系。

     2、在指令内部,$modelValue其实便是test值的一份拷贝。

     3、大家通过$formatters()方法将$modelValue转变成$viewValue。

     4、然后调用$render()方法将$viewValue渲染到directive
template中。

    
5、当大家经过某种门路监察和控制到指令模板中的变量发生变化之后,大家调用$setViewValue()来更新$viewValue。

    
6、与(4)相对应,大家透过$parsers方法将$viewValue转化成$modelValue。

     7、当$modelValue产生变化后,则会去创新HelloApp的UI。

全盘指令逻辑

依据上面包车型客车流程,大家先来将$modelValue转化成$viewValue,然后在命令模板中举办渲染。

// $formatters接受一个数组
// 数组是一系列方法,用于将modelValue转化成viewValue
ngModelController.$formatters.push(function(modelValue) {
 var unit = 'minutes', num = 0, i, unitName;
 modelValue = parseInt(modelValue || 0);

 for (i = multiplierTypes.length-1; i >= 0; i--) {
 unitName = multiplierTypes[i];

 if (modelValue % multiplierMap[unitName] === 0) {
  unit = unitName;
  break;
 }
 }

 if (modelValue) {
 num = modelValue / multiplierMap[unit];
 }

 return {
 unit: unit,
 num: num
 };
});

末尾回到的对象便是$viewValue的value。(当然$viewValue还有别的的片段本性。)

其次步,大家调用$render方法将$viewValue渲染到指令模板中去。

// $render用于将viewValue渲染到指令的模板中
ngModelController.$render = function() {
 scope.unit = ngModelCtrl.$viewValue.unit;
 scope.num = ngModelCtrl.$viewValue.num;
};

其三步,大家由此$watch来监督指令模板中num和unit变量。当其发生变化时,咱们须求立异$viewValue。

scope.$watch('unit + num', function() {
// $setViewValue用于更新viewValue
 ngModelController.$setViewValue({
 unit: scope.unit,
 num: scope.num
 });
});

第四步,大家通过$parsers将$viewValue->$modelValue。

// $parsers接受一个数组
// 数组是一系列方法,用于将viewValue转化成modelValue
ngModelController.$parsers.push(function(viewValue) {
 var unit = viewValue.unit;
 var num = viewValue.num;
 var multiplier;

 multiplier = multiplierMap[unit];

 return num * multiplier;
});

总结

好了,到那贰个双面包车型客车数额绑定逻辑就创立了。不掌握我们都学会了吧?希望本文的剧情对大家的学习只怕干活能带动一定的帮忙,假如有问号大家能够留言调换。

你或者感兴趣的篇章:

  • 详谈AngularJs
    调控器、数据绑定、成效域
  • 深切浅析AngularJS中的三回性数据绑定
    (bindonce)
  • AngularJS1.X上学笔记2-数据绑定详解
  • AngularJS框架中的双向数据绑定机制详解【裁减必要再次的开拓代码量】
  • AngularJS入门教程之数据绑定原理详解
  • AngularJS入门教程之数据绑定用法示例
  • AngularJS
    双向数据绑定详解简单实例
  • 详解JavaScript的AngularJS框架中的功效域与数量绑定
  • angularjs学习笔记之双向数据绑定
  • Angularjs中数据绑定的实例详解