angular.DelegateService来返回一个代理服务,指令将接口注册到代理服务,控制器调用代理服务中的接口即可操作指令从而操作dom元素。| 1 2 3 4 5 6 7 | angular.DelegateService = function (methodNames) { //... return ["$log", function ($log) { //... return new DelegateService(); }]; }; |
angular了,在此之上添加函数,就可以在模块定义的时候使用。这个函数返回的是标准的声明service的数组,前面一个$log服务,后面一个实现函数。而这个服务本身就是新创建的DelegateService实例。methodNames参数有什么用处。methodNames看名字就可以知道这是一个数组,包含了一些函数的名称(字符串)。| 1 2 3 | if (methodNames.indexOf("$getByHandle") > -1) { throw new Error("Method "$getByHandle" is implicitly added to each delegate service. Do not list it as a method."); } |
$getByHandle和自定义的函数冲突。| 1 2 3 | methodNames.forEach(function (methodName) { DelegateInstance.prototype[methodName] = instanceMethodCaller(methodName); }); |
prototype上。| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | function instanceMethodCaller(methodName) { return function caller() { var handle = this.handle, args = arguments, foundInstancesCount = 0, returnValue; this._instances.forEach(function (instance) { if ((!handle || handle === instance.$$delegateHandle) && instance.$$filterFn(instance)) { foundInstancesCount++; var ret = instance[methodName].apply(instance, args); if (foundInstancesCount === 1) { returnValue = ret; } } }); if (!foundInstancesCount && handle) { return $log.warn("Delegate for handle "" + handle + "" could not find a " + "corresponding element with id/delegate="" + handle + ""! " + methodName + "() was not called! " + "Possible cause: If you are calling " + methodName + "() immediately, and " + "your element with delegate-handle="" + handle + "" is a child of your " + "controller, then your element may not be compiled yet. Put a $timeout " + "around your call to " + methodName + "() and try again."); } return returnValue; }; } |
caller函数,这个函数就是遍历_instances中的实例,然后匹配函数名称,调用并返回结果。默认返回第一个实例或者指定的实例。下面来看看这个实例。| 1 2 3 4 | function DelegateInstance(instances, handle) { this._instances = instances; this.handle = handle; } |
_instances这个数组来保存实例。至于handle可以理解为实例id。| 1 | DelegateService.prototype = DelegateInstance.prototype; |
DelegateInstance的原型复制到DelegateService上。| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | function trueFn() { return true; } DelegateService.prototype._registerInstance = function (instance, handle, filterFn) { var instances = this._instances; instance.$$delegateHandle = handle; instance.$$filterFn = filterFn || trueFn; instances.push(instance); return function deregister() { var index = instances.indexOf(instance); if (index !== -1) { instances.splice(index, 1); } }; }; |
DelegateService的原型上声明了一个函数_registerInstance用来注册服务。该函数将服务保存在代理服务中,同时返回一个注销服务的函数。filterFn实际上就是一个过滤函数,如果实例中拥有私有函数,可以通过自定义过滤函数,只暴露公有函数。| 1 2 3 | DelegateService.prototype.$getByHandle = function (handle) { return new DelegateInstance(this._instances, handle); }; |
handle这个id来获取实例。| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 | angular.module("directive", []).directive("keyboard", ["keyboardService", function (keyboardService) { return { replace: true, templateUrl: "template/keyboard.html", link: function (scope, elm, attrs) { var instance = { toggle: function (flag) { window.console.log(flag); } }; keyboardService._registerInstance(instance); } }; }]).service("keyboardService", angular.DelegateService(["toggle"])); |
| 1 2 3 | angular.module("app", ["directive"]).controller("ctrl", ["$scope", "keyboardService", function($scope, keyboardService){ keyboardService.toggle(true); }]); |