如何在Angular 5混合应用中使用AngularJS控制器
Angular与AngularJS混合应用:在Angular组件中调用AngularJS控制器
刚好踩过Angular和AngularJS混合迁移的坑,给你分享下具体实现方法,亲测可行~
一、先搞定混合环境的基础配置
首先得把Angular和AngularJS的混合环境搭起来,核心用官方的@angular/upgrade/static包:
- 先安装依赖:
npm install @angular/upgrade --save - 在Angular根模块中导入
UpgradeModule,并启动AngularJS模块:
import { NgModule } from '@angular/core'; import { BrowserModule } from '@angular/platform-browser'; import { UpgradeModule } from '@angular/upgrade/static'; import { AppComponent } from './app.component'; // 引入你的AngularJS主模块 import { angularJSModule } from './angularjs/app.module'; @NgModule({ declarations: [AppComponent], imports: [BrowserModule, UpgradeModule], providers: [], bootstrap: [AppComponent] }) export class AppModule { constructor(private upgrade: UpgradeModule) {} ngDoBootstrap() { // 启动AngularJS模块,开启strictDi避免隐式依赖 this.upgrade.bootstrap(document.body, [angularJSModule.name], { strictDi: true }); } }
二、方法1:直接在Angular组件中实例化AngularJS控制器
如果不想动现有AngularJS控制器的代码,可以直接在Angular组件里通过AngularJS的$controller服务实例化控制器:
1. 现有AngularJS控制器示例
假设你有一个已存在的控制器:
angular.module('angularJSModule') .controller('OldAngularJSController', function($scope) { // 控制器方法 this.sayHello = function(name) { return `Hello, ${name}! 来自AngularJS控制器`; }; // 控制器数据 this.userData = { username: 'AngularJS老用户' }; });
2. 在Angular组件中调用控制器
通过UpgradeModule获取AngularJS注入器,进而实例化控制器并调用其方法:
import { Component, OnInit } from '@angular/core'; import { UpgradeModule } from '@angular/upgrade/static'; @Component({ selector: 'app-angular-wrapper', template: ` <h3>我是Angular组件</h3> <p>调用AngularJS控制器方法的结果:{{ greeting }}</p> <p>AngularJS控制器的数据:{{ userData.username }}</p> ` }) export class AngularWrapperComponent implements OnInit { greeting: string; userData: any; constructor(private upgrade: UpgradeModule) {} ngOnInit() { // 获取AngularJS注入器 const ng1Injector = this.upgrade.injector; // 获取AngularJS的$controller服务 const $controller = ng1Injector.get('$controller'); // 创建新的AngularJS scope(控制器依赖$scope) const $scope = ng1Injector.get('$rootScope').$new(); // 实例化AngularJS控制器 const oldController = $controller('OldAngularJSController', { $scope: $scope }); // 调用控制器方法 this.greeting = oldController.sayHello('Angular新用户'); // 获取控制器数据 this.userData = oldController.userData; } }
三、方法2:通过升级AngularJS指令获取控制器实例
如果你的AngularJS控制器是某个指令的控制器,可以先把指令升级为Angular可用的指令,再通过ViewChild获取控制器实例:
1. 现有AngularJS指令示例
angular.module('angularJSModule') .directive('userInfoDirective', function() { return { controller: 'OldAngularJSController', template: '<div>AngularJS指令模板:{{ $ctrl.userData.username }}</div>' }; });
2. 升级AngularJS指令为Angular指令
创建Angular指令继承自UpgradeComponent,包装原AngularJS指令:
import { Directive, ElementRef, Injector } from '@angular/core'; import { UpgradeComponent } from '@angular/upgrade/static'; @Directive({ selector: 'user-info-directive' }) export class UserInfoDirectiveUpgrade extends UpgradeComponent { constructor(elementRef: ElementRef, injector: Injector) { // 第一个参数是AngularJS指令的名称 super('userInfoDirective', elementRef, injector); } }
记得在Angular模块的declarations中注册这个升级后的指令。
3. 在Angular组件中使用并获取控制器
import { Component, OnInit, ViewChild } from '@angular/core'; import { UserInfoDirectiveUpgrade } from './user-info-directive-upgrade.directive'; @Component({ selector: 'app-angular-component', template: ` <h3>我是Angular组件</h3> <user-info-directive #userDirective></user-info-directive> <p>从指令控制器拿到的问候:{{ greeting }}</p> ` }) export class AngularComponent implements OnInit { @ViewChild('userDirective') userDirective: UserInfoDirectiveUpgrade; greeting: string; ngOnInit() { // 通过指令的instance属性获取AngularJS控制器实例 const oldController = this.userDirective.instance; this.greeting = oldController.sayHello('Angular用户'); } }
四、更推荐的长期方案:抽离服务而非直接调用控制器
直接调用控制器只是临时方案,更推荐把AngularJS控制器的业务逻辑抽成服务,再升级到Angular中使用:
1. 抽离AngularJS服务
angular.module('angularJSModule') .service('userService', function() { this.getGreeting = function(name) { return `Hello, ${name}! 来自AngularJS服务`; }; this.getUserData = function() { return { username: 'AngularJS老用户' }; }; });
2. 升级服务到Angular
import { Injectable } from '@angular/core'; import { upgradeInjectable } from '@angular/upgrade/static'; @Injectable() export class UserService extends upgradeInjectable('userService') {}
在Angular模块的providers中注册服务后,就可以像普通Angular服务一样注入使用:
import { Component, OnInit } from '@angular/core'; import { UserService } from './user.service'; @Component({ selector: 'app-angular-component', template: ` <h3>我是Angular组件</h3> <p>{{ greeting }}</p> <p>{{ userData.username }}</p> ` }) export class AngularComponent implements OnInit { greeting: string; userData: any; constructor(private userService: UserService) {} ngOnInit() { this.greeting = this.userService.getGreeting('Angular用户'); this.userData = this.userService.getUserData(); } }
五、注意事项
- 变更检测问题:Angular和AngularJS的变更检测机制不同,若在Angular中操作AngularJS数据,可能需要手动调用
$scope.$apply()或用Angular的NgZone包裹操作,确保视图更新。 - 逐步迁移:混合应用只是过渡方案,尽量逐步把AngularJS逻辑迁移到Angular中,避免长期依赖混合调用,降低维护成本。
- 严格依赖注入:开启
strictDi可避免AngularJS中的隐式依赖,让代码更规范,也方便后续迁移。
内容的提问来源于stack exchange,提问作者shyam_
相关产品推荐
相关产品推荐

