MVC5项目混合Angular 4组件与传统视图的实现方案咨询
刚好我之前在项目里实现过MVC5 + Angular 4的混合开发模式——既保留传统MVC视图渲染大部分内容,又能按需嵌入独立的Angular组件/模块,完全不是只能做SPA。给你梳理几个经过实践验证的可行方案:
这是最直接的方式,把每个业务区域的Angular模块单独打包成UMD格式(兼容全局变量、AMD、CommonJS),然后在对应的MVC视图里按需加载并初始化。
具体步骤:
配置Angular项目打包为UMD
针对Angular 4(用angular-cli的话是老版本@angular/cli),修改.angular-cli.json的apps配置,指定每个业务模块的入口,并设置输出格式为UMD:{ "apps": [ { "name": "order-module", "root": "src/app/modules/order", "outDir": "../MVCProject/wwwroot/angular-modules/order", "main": "order.module.ts", "tsconfig": "tsconfig.app.json", "environmentSource": "environments/environment.ts", "environments": { "dev": "environments/environment.ts", "prod": "environments/environment.prod.ts" }, "outputPath": "../MVCProject/wwwroot/angular-modules/order", "deployUrl": "/angular-modules/order/", "format": "umd" } ] }执行
ng build --prod后,会在MVC项目的wwwroot/angular-modules/order下生成打包好的UMD文件(比如order-module.umd.js)。在MVC视图中引入并初始化
打开需要嵌入Angular组件的MVC视图(比如Views/Order/Index.cshtml),先引入Angular的核心依赖,再引入打包好的UMD模块,最后添加占位符并初始化:<!-- 引入Angular核心依赖 --> <script src="~/lib/core-js/client/shim.min.js"></script> <script src="~/lib/zone.js/dist/zone.js"></script> <script src="~/lib/systemjs/dist/system.src.js"></script> <!-- 引入打包好的业务模块UMD文件 --> <script src="~/angular-modules/order/order-module.umd.js"></script> <!-- Angular组件占位符 --> <div id="order-component-container"> <app-order></app-order> </div> <!-- 初始化Angular模块 --> <script> document.addEventListener('DOMContentLoaded', function() { // UMD模块会暴露全局变量,直接调用bootstrapModule platformBrowserDynamic().bootstrapModule(window.OrderModule); }); </script>注意:Angular模块的根组件选择器要和占位符里的标签一致(比如
app-order)。
如果多个MVC视图都需要嵌入Angular组件,可以把Angular的核心依赖放到MVC的布局页(_Layout.cshtml)里,避免重复加载,提升性能。
具体步骤:
在布局页引入Angular核心依赖
在_Layout.cshtml的底部引入核心UMD包:<script src="~/lib/core-js/client/shim.min.js"></script> <script src="~/lib/zone.js/dist/zone.js"></script> <script src="~/lib/@angular/core/bundles/core.umd.js"></script> <script src="~/lib/@angular/common/bundles/common.umd.js"></script> <script src="~/lib/@angular/platform-browser/bundles/platform-browser.umd.js"></script> <script src="~/lib/@angular/platform-browser-dynamic/bundles/platform-browser-dynamic.umd.js"></script>局部视图引入业务模块并初始化
每个需要嵌入组件的MVC视图只需要引入对应的业务模块UMD文件,添加占位符并初始化即可:<!-- 业务模块UMD文件 --> <script src="~/angular-modules/customer/customer-module.umd.js"></script> <!-- 组件占位符 --> <app-customer></app-customer> <!-- 初始化 --> <script> document.addEventListener('DOMContentLoaded', () => { platformBrowserDynamic().bootstrapModule(window.CustomerModule); }); </script>
如果想让Angular组件像普通HTML标签一样嵌入MVC视图,不用手动初始化模块,可以用Web Components方案。不过Angular 4本身没有官方的@angular/elements,需要借助第三方库@webcomponents/custom-elements来兼容。
具体步骤:
安装兼容库并配置Angular组件
安装依赖:npm install @webcomponents/custom-elements --save在Angular模块里把组件注册为自定义元素:
import { NgModule, Injector } from '@angular/core'; import { BrowserModule } from '@angular/platform-browser'; import { CustomerComponent } from './customer.component'; import { createCustomElement } from '@angular/elements'; // 需安装第三方polyfill适配Angular 4 @NgModule({ declarations: [CustomerComponent], imports: [BrowserModule], entryComponents: [CustomerComponent] // 必须声明为入口组件 }) export class CustomerModule { constructor(private injector: Injector) { const customerElement = createCustomElement(CustomerComponent, { injector }); customElements.define('customer-component', customerElement); } ngDoBootstrap() {} // 禁用自动引导,因为是自定义元素 }打包并嵌入MVC视图
打包组件后,在MVC视图里引入打包文件和兼容库,直接使用自定义标签:<script src="~/lib/@webcomponents/custom-elements/custom-elements.min.js"></script> <script src="~/angular-modules/customer/customer-module.umd.js"></script> <!-- 直接用自定义标签嵌入组件 --> <customer-component></customer-component>
- 路由冲突:Angular组件内部的路由建议使用
HashLocationStrategy,避免和MVC的服务器端路由冲突。在Angular模块里配置:import { LocationStrategy, HashLocationStrategy } from '@angular/common'; @NgModule({ providers: [{ provide: LocationStrategy, useClass: HashLocationStrategy }] }) - 资源路径:确保Angular打包后的资源路径正确,可通过Angular的
deployUrl配置指定。 - 版本兼容:Angular 4比较老旧,部分新特性需要额外polyfill,优先考虑方案一或方案二更稳妥。
内容的提问来源于stack exchange,提问作者JensB

