AngularJS指令控制器继承:如何复用全局指令并覆盖部分函数
实现AngularJS指令的复用与部分覆盖
这个需求在AngularJS里其实很常见,咱们可以通过两种主流方式来实现——要么利用指令的继承特性复用父指令的逻辑,要么把公共代码抽离到服务里,让多个指令共享。我给你详细拆解下:
方案一:通过指令继承(Require父指令Controller)
这种方式适合你想让子指令和父指令保持强关联,直接复用父指令里的方法,同时覆盖部分逻辑的场景。
首先咱们先完善你的父指令,把可复用的方法放到它的Controller里(Controller是指令间共享逻辑的最佳载体):
'use strict'; angular.module('app.leaderBoardDirective') .directive('fooLeaderBoard', LeaderBoard); LeaderBoard.$inject = []; function LeaderBoard() { var directive = { restrict: 'EA', replace: false, templateUrl: 'foo/leaderBoard.tpl.html', controller: LeaderBoardController, controllerAs: 'vm', bindToController: true // 把属性绑定到控制器实例 }; return directive; } LeaderBoardController.$inject = []; function LeaderBoardController() { var vm = this; // 全局公共方法:获取排行榜基础数据 vm.getLeaderBoardData = function() { console.log('执行全局默认的获取数据逻辑'); return [{name: 'User1', score: 100}, {name: 'User2', score: 90}]; }; // 全局公共方法:渲染排行榜 vm.renderBoard = function(data) { console.log('用全局逻辑渲染排行榜:', data); // 这里是默认渲染逻辑 }; }
接下来创建你的子指令,通过require属性获取父指令的Controller,然后就可以复用父方法,同时覆盖需要自定义的部分:
'use strict'; angular.module('app.leaderBoardDirective') .directive('barLeaderBoard', BarLeaderBoard); BarLeaderBoard.$inject = []; function BarLeaderBoard() { var directive = { restrict: 'EA', replace: false, templateUrl: 'bar/barLeaderBoard.tpl.html', // 可自定义模板,也可复用父模板 require: '^fooLeaderBoard', // 向上查找父指令的Controller controller: BarLeaderBoardController, controllerAs: 'barVm', bindToController: true, link: function(scope, element, attrs, parentCtrl) { // 将父控制器传递给子控制器,方便子控制器调用父方法 scope.barVm.parentCtrl = parentCtrl; } }; return directive; } BarLeaderBoardController.$inject = []; function BarLeaderBoardController() { var vm = this; // 覆盖父指令的获取数据方法,同时复用父方法的基础逻辑 vm.getLeaderBoardData = function() { // 先调用父方法拿到基础数据 var baseData = vm.parentCtrl.getLeaderBoardData(); console.log('为当前页面自定义修改数据'); // 这里添加你的自定义逻辑 baseData.push({name: '当前页专属用户', score: 95}); return baseData; }; // 直接复用父指令的渲染方法 vm.renderCustomBoard = function() { var customData = vm.getLeaderBoardData(); vm.parentCtrl.renderBoard(customData); // 调用父指令的公共渲染逻辑 }; }
方案一优势:
- 父指令的全局逻辑完全保留,子指令按需覆盖即可
- 通过
require机制轻松获取父指令的Controller,复用成本低 - 子指令可以拥有独立模板,也可以和父指令共用模板
方案二:抽离公共逻辑到服务
如果你的公共逻辑需要被多个指令、甚至控制器复用,把逻辑抽离到AngularJS服务里会更灵活,也更符合代码解耦的原则。
首先创建一个公共服务,存放所有可复用的逻辑:
'use strict'; angular.module('app.leaderBoardDirective') .service('LeaderBoardService', LeaderBoardService); LeaderBoardService.$inject = []; function LeaderBoardService() { var service = this; // 公共方法:获取基础排行榜数据 service.getBaseData = function() { console.log('获取全局基础排行榜数据'); return [{name: 'User1', score: 100}, {name: 'User2', score: 90}]; }; // 公共方法:基础渲染逻辑 service.renderBaseBoard = function(data) { console.log('用全局基础逻辑渲染:', data); }; }
然后修改父指令,注入这个服务并调用公共方法:
'use strict'; angular.module('app.leaderBoardDirective') .directive('fooLeaderBoard', LeaderBoard); LeaderBoard.$inject = ['LeaderBoardService']; function LeaderBoard(LeaderBoardService) { var directive = { restrict: 'EA', replace: false, templateUrl: 'foo/leaderBoard.tpl.html', controller: LeaderBoardController, controllerAs: 'vm', bindToController: true }; return directive; function LeaderBoardController() { var vm = this; vm.getLeaderBoardData = function() { return LeaderBoardService.getBaseData(); }; vm.renderBoard = function(data) { LeaderBoardService.renderBaseBoard(data); }; } }
最后创建子指令,同样注入服务,按需复用或覆盖逻辑:
'use strict'; angular.module('app.leaderBoardDirective') .directive('barLeaderBoard', BarLeaderBoard); BarLeaderBoard.$inject = ['LeaderBoardService']; function BarLeaderBoard(LeaderBoardService) { var directive = { restrict: 'EA', replace: false, templateUrl: 'bar/barLeaderBoard.tpl.html', controller: BarLeaderBoardController, controllerAs: 'barVm', bindToController: true }; return directive; function BarLeaderBoardController() { var vm = this; // 自定义获取数据逻辑,复用服务的基础数据 vm.getLeaderBoardData = function() { var baseData = LeaderBoardService.getBaseData(); // 添加当前页面的自定义数据 baseData.push({name: '当前页专属用户', score: 95}); return baseData; }; // 复用服务的基础渲染逻辑,同时添加自定义渲染步骤 vm.renderBoard = function(data) { LeaderBoardService.renderBaseBoard(data); console.log('为当前页面添加额外渲染逻辑'); }; } }
方案二优势:
- 公共逻辑完全解耦,任何组件(指令、控制器、过滤器)都可以复用
- 修改公共逻辑只需要修改服务,无需改动多个指令
- 子指令的自由度更高,可以完全重写逻辑,也可以部分复用
内容的提问来源于stack exchange,提问作者Krigan
相关产品推荐
相关产品推荐

