歡迎來到Linux教程網
Linux教程網
Linux教程網
Linux教程網
您现在的位置: Linux教程網 >> UnixLinux >  >> Linux編程 >> Linux編程

Angular中用代理服務實現控制器與指令之間的通信

場景

一般來說,angular中,控制器與指令之間的通信可以通過共享作用域的方式來實現。這種處理方式可以滿足大部分需求,但是比如說指令如果是獨立作用域的話這種情況就玩不轉了~在開發中就碰到這樣一種尴尬的情況:控制器想要操作某個dom元素(滾動或者獲取元素坐標),angular中是不提倡在控制器中直接操作dom而是在指令中。這個時候就可以通過一個代理服務來實現。

代理服務

這一段代理服務的代碼短小精悍,從著名的ionic中拷貝出來。
大致思路是通過angular.DelegateService來返回一個代理服務,指令將接口注冊到代理服務,控制器調用代理服務中的接口即可操作指令從而操作dom元素。

擴展Angular屬性

1
2
3
4
5
6
7
angular.DelegateService = function (methodNames) {
//...
return ['$log', function ($log) {
//...
return new DelegateService();
}];
};

angular中最全局的全局變量當然就是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!\n' + '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);
}]);

代理服務源碼

https://github.com/driftyco/ionic/blob/master/js/utils/delegateService.js

一些AngularJS相關文章鏈接

AngularJS權威教程 清晰PDF版  http://www.linuxidc.com/Linux/2015-01/111429.htm

希望你喜歡,並分享我的工作~帶你走近AngularJS系列

  1. 帶你走近AngularJS - 基本功能介紹 http://www.linuxidc.com/Linux/2014-05/102140.htm
  2. 帶你走近AngularJS - 體驗指令實例 http://www.linuxidc.com/Linux/2014-05/102141.htm
  3. 帶你走近AngularJS - 創建自定義指令 http://www.linuxidc.com/Linux/2014-05/102142.htm

如何在 AngularJS 中對控制器進行單元測試 http://www.linuxidc.com/Linux/2013-12/94166.htm

在 AngularJS 應用中通過 JSON 文件來設置狀態 http://www.linuxidc.com/Linux/2014-07/104083.htm

AngularJS 之 Factory vs Service vs Provider http://www.linuxidc.com/Linux/2014-05/101475.htm

AngularJS —— 使用 ngResource、RESTful APIs 和 Spring MVC 框架提交數據 http://www.linuxidc.com/Linux/2014-07/104402.htm

AngularJS 的詳細介紹:請點這裡
AngularJS 的下載地址:請點這裡

Copyright © Linux教程網 All Rights Reserved