概述
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属性则需要使用双花括号括起来。
网友评论