如何封装和复用AngularJS的代码
发布于 6 年前 作者 CodeingShow 5718 次浏览 来自 问答

(场景是:有很多个controller,每个controller内部的代码除了controller的名称以外全部都一样,只需要把名称换一下。但是我不想复制粘贴几十个这样的controller)

Angular代码如何封装复用1.pngAngular代码如何封装复用2.png

26 回复

写成指令?

来自酷炫的 CNodeMD

@luanxuechao 我去学习一下怎么写成指令

很久没写过AngularJS了,凭记忆回答:

AngularJS早就支持Component的写法了

每个controller内部的代码除了controller的名称以外全部都一样,只需要把名称换一下

那么建议封装service, 然后注入到controller里面

如果是逻辑与模板都要复用: 那么封装成Component 如果就逻辑复用,模板不复用: 封装成指令或service,跟业务相关都,都应该分装成service

就一个地方不一样的话,把这个东西作为参数传进去

<Component tag="AST">
<Component tag="Log">

Component既可以是组件,也可以是指令.

Angular在1.6x前,写组件都是指令附带模板,然后出了Component,可以很方便的定义一个组件了

@axetroy 主要是不是很会封装service,我之前写了一个,发现没用。这是controller的代码,类似于这样的controller一共要写几十个,区别就是代码里面的“ATS”换成其他的字符串。您能给一下具体service怎么写吗?然后我再去看一下你说的component。

	app.controller("ATS", function($scope,$http) {
		$http.get("${contextPath}/uhostmanage/checkManage/testItem?testItem=ATS").success(function (response) {
		$scope.ATS = response;
		$scope.isAll = true;//全选框默认选中
		$scope.All = true;//默认显示“取消全选”
		$scope.selected = [];//用于保存选中的复选框的id

		angular.forEach($scope.ATS, function(data){$scope.selected.push(data.id);});
		$scope.isSelected = function(id){return $scope.selected.indexOf(id)>=0;};

		$scope.updateSelection = function($event, id){
			var action = ($event.target.checked?'checked':'unchecked');
			if(action === 'checked' && $scope.selected.indexOf(id) === -1){
				$scope.selected.push(id);
			}
			if(action === 'unchecked' && $scope.selected.indexOf(id)!==-1){
				var idx = $scope.selected.indexOf(id);
				$scope.selected.splice(idx,1);
			}

			if($scope.selected.length === $scope.ATS.length){
				$scope.isAll = true;
				$scope.All = true;
			}else{
				$scope.isAll = false;
				$scope.All = false;
			}
		};

		$scope.selectAll = function ($event) {
			if($event.target.checked){
				$scope.selected.length = 0;//记得要先清空数组
				angular.forEach($scope.ATS, function(data){$scope.selected.push(data.id);});
				$scope.All = true;
			}else {
				$scope.selected.length = 0;
				$scope.All = false;
			}
		};
});});

![406ae2f3-6005-4e4e-8ebf-511bd9d8fdac.png](//static.cnodejs.org/FhdplX2lMObuPBMzhGe9Ofk1Abhh)

@axetroy image.png 页面中对应的代码也是大量的重复,反正就是大同小异,我也想把页面上的这么多controller只写一个,然后传参数进去,js部分也去掉这么多重复代码。

@CodeingShow Component和指令都能满足你的需求. 甚至Controller都行,都可以接收参数。 多翻文档,多Google。

也别发邮件给我了,给你指了个方向,自己解决

@axetroy 搞了一天没成功,还是复制粘贴吧

父级广播一个字段给你的子控制器不就能区分吗?

//父控制器
$scope.$broadcast 'appendChild',childA  <---区分子控制器的字段

//子控制器
$scope.$on 'appendChild',(e,child)=>{
	//do something with 'child'
}

@qichangjun 每个子控制器的监听器的名字(appendChild)应该是不一样的,否则父作用域发广播,所有子作用域都会接收广播。而每个子作用域我都是使用指令实现的

没那么难吧…

像这种只有一个地方不同的,有大把方式传入变量。

直接写在controller的Dom上,可以写在指令的参数,可以定义成Component

然后像上面菜单栏,定好一个数组,ng-for完事

来自酷炫的 CNodeMD

@axetroy 其实我使用指令已经做完了百分之八十,传入变量在有些地方不能使用变量,我的业务需求不是简单的传个变量进去替换掉不同的字符串那么简单呀。

	<div ng-controller="parentCtrl">
		<div ng-controller="childCtrl as vm">	 </di>
	</div>
	//childCtrl 里的$scope作用域是parentCtrl的,vm则是自己的作用域

@qichangjun 如果子控制器是一个指令呢?

那就用双向绑定吧 directive = restrict: 'E’ templateUrl: 'xx.html?' scope: bindDataA : ‘=‘ controller: [’$scope’,ctrlFun] controllerAs: ‘vm’

然后指令内部用 $scope.$watch监听变化

@qichangjun 还有一个问题:假如说封装一个指令,其模板用ng-if控制,且默认ng-if = false(意味着一开始的时候DOM树上没有这个模板)

疑问是:既然DOM树上没有这个模板,父控制器就不能给这个指令发广播呀,那我应该怎么做才能在父控制器中通过一个按钮来激活这个指令(即ng-if = true)使其显示在dom树上呢???(前提是不用ng-show或者ng-hide)

你这个ng-if到底是加在哪里的?如果加在指令外层或指令元素上,那你的父控制器就可以直接控制,如果是加在指令内部的模版上那指令的这个dom就一直是在dom树上的,你的广播是可以监听到的

	<div id="parent">
		<child ng-if="bool"></child>   //这里的bool可以直接在父控制器上控制
	</div>
	-----------------------------------------
	<div id="parent">
		<child > </child>
	</div>
	child的template : '<div ng-if="bool"></div>'    //初始化时child的dom就存在,child的指令可以接受广播

ps:如果你在第一种情况下想让ng-if改为true的同时触发一个广播让指令能接受到,就用$timeout触发广播

@qichangjun 非常感谢!非常感谢!非常感谢!,$timeout终于解决了困扰已久的问题。之前必须点击两次按钮,第一次只是ng-if变为了true,第二次才发广播。我的疑问是:不是连续执行的吗?为什么不延时发广播就不执行呢???

不过,在用$timeout之前,我用了一个很傻比的方法,如下图: b5bb3a23-7775-46fe-9489-bae83cc01131.png

@qichangjun image.png 这种场景困扰了我至少三天没有解决,快崩溃了。多谢多谢。

其实就是在你ng-if设为true时,你的directive的js初始化是放在最后处理的,所以当你触发广播时,其实directive的js还并没有被初始化,也就是还没有执行广播监听这段代码时,广播就已经发出去了 而$timeout在不设置时间参数时的作用就是让函数内的这段js放到最后处理,也就是在监听代码执行后才发出广播,这样自然就能监听到广播了,其实angularjs的坑很多,所以尽快转到ng2是个明知的选择

回到顶部