美文网首页
Angular JS中ng属性的实现细节

Angular JS中ng属性的实现细节

作者: yb_剑笙 | 来源:发表于2016-09-10 23:11 被阅读0次

    概述

    Angular JS为很多属性实现了对应的directive。通过[ng-]开头的属性实现对应的属性与scope数据进行绑定。如:ng-disabled='enabled'就会把scope.enabled与元素的disabled属性进行绑定。改变scope.enabled的值,元素的disabled属性的值也会变化。

    支持的属性

    第一类总共有12个属性,如下:

    属性 ng属性
    selected ng-selected
    checked ng-checked
    disabled ng-disabled
    readOnly ng-readonly
    required ng-required
    open ng-open
    minlength ng-minlength
    maxlength ng-maxlength
    min ng-min
    max ng-max
    pattern ng-pattern
    step ng-step

    在这一类中,directive会去利用$scope的watcher方法监控数据模型,如果有变动,就会设置属性值。需要注意的是ng-checked和ng-module绑定了相同的值,ng-checked将会失效。

    第二类总共有3个,如下:

    属性 ng属性
    src ng-src
    srcset ng-srcset
    href/xlink:href ng-href

    在这一类中,directive会利用attr的$observe方法监控ng属性值的变化,然后再去设置属性值,同时还会把值写入元素的property中去。需要注意的是ng-href实现了普通元素和SVG元素的统一处理。

    实现细节

    第一类ng属性有两种实现方式,其实现本质上是一样的,关键代码:

    forEach(BOOLEAN_ATTR, function(propName, attrName) {  
    // binding to multiple is not supported  
        if (propName === 'multiple')
            return;  
        function defaultLinkFn(scope, element, attr) {   
            cope.$watch(attr[normalized], function ngBooleanAttrWatchAction(value) {
                attr.$set(attrName, !!value);   
            });
        }
        var normalized = directiveNormalize('ng-' + attrName);  
        var linkFn = defaultLinkFn;  
        if (propName === 'checked') {    
            linkFn = function(scope, element, attr) { 
            // ensuring ngChecked doesn't interfere with ngModel when both are set on the same input     
                if (attr.ngModel !== attr[normalized]) {        
                    defaultLinkFn(scope, element, attr);      
                }
            };
        }
        ngAttributeAliasDirectives[normalized] = function() {
            return {
                restrict: 'A',
                priority: 100,
                link: linkFn    
            };  
        };
    });
    
    // aliased input attrs are evaluatedforEach(ALIASED_ATTR, function(htmlAttr, ngAttr) {
      ngAttributeAliasDirectives[ngAttr] = function() {
        return {
          priority: 100,
          link: function(scope, element, attr) {
            //special case ngPattern when a literal regular expression value
            //is used as the expression (this way we don't have to watch anything).
            if (ngAttr === 'ngPattern' && attr.ngPattern.charAt(0) === '/') {
              var match = attr.ngPattern.match(REGEX_STRING_REGEXP);
              if (match) {
                attr.$set('ngPattern', new RegExp(match[1], match[2]));
                return; 
             }
            }
            scope.$watch(attr[ngAttr], function ngAttrAliasWatchAction(value) {
              attr.$set(ngAttr, value);
            });
          }
        };
      };
    });
    

    其中最为关键的是directive中的link函数里的内容:

    scope.$watch(attr[ngAttr], function ngAttrAliasWatchAction(value) {
       attr.$set(ngAttr, value); 
    });
    

    在这里实现了对数据的监控,以及变化时的处理。
    第二类在实现的时候和第一种大同小异,有区别的也是directive的link函数:

    link: function(scope, element, attr) {
      var propName = attrName, 
      name = attrName;
      if (attrName === 'href' &&      toString.call(element.prop('href')) === '[object SVGAnimatedString]') {
        name = 'xlinkHref';
        attr.$attr[name] = 'xlink:href';
        propName = null; 
      }
      attr.$observe(normalized, function(value) {
        if (!value) {
          if (attrName === 'href') {
            attr.$set(name, null);
          }
          return;
        }
        attr.$set(name, value); 
        // on IE, if "ng:src" directive declaration is used and "src" attribute doesn't exist
        // then calling element.setAttribute('src', 'foo') doesn't do anything, so we need
        // to set the property as well to achieve the desired effect.
        // we use attr[attrName] value since $set can sanitize the url.
        if (msie && propName) element.prop(propName, attr[name]);
      });
    

    这里面实现的功能稍微多一点点,首先会针对href属性进行SVG的兼容,然后通过attr的$observe方法监控属性值的变化。在属性值发生变化时首先会设置到attr中去,然后会根据需要设置到element的property中去。

    使用样例

    <!DOCTYPE html><html lang="en" ng-app="app">
    <!--<html>-->
    <head>
        <title>Test</title>
    </head>
    <body ng-controller="testCtrl">
    <div>
        <input ng-readonly="enable" ng-model="data">
        <input type="button" value="click" ng-click="enable=!enable">
    </div>
    <div>
        <a ng-href="{{data}}">link</a>
    </div>
    </body>
    <script src="./node_modules/angular/angular.js" type="text/javascript"></script>
    <script>
        angular.module("app",[]).controller("testCtrl",["$scope",function($scope){
            $scope.enable = false;
            $scope.data = "";
        }]);
    </script>
    </html>
    

    在这个样例中实现了点击按钮禁用或启用输入框,在输入框中输入数据会改变a标签的href属性值。
    从中可以看到,对于第一类ng属性可以直接写数据名称,而对于第二类ng属性则需要使用双花括号括起来。

    相关文章

      网友评论

          本文标题:Angular JS中ng属性的实现细节

          本文链接:https://www.haomeiwen.com/subject/vdzyettx.html