如何在 .NET Core Angular VS2017 模板中实现 angular-mdc-web

How to implement angular-mdc-web in .NET Core Angular VS2017 Template

我正在尝试让 angular-mdc-web 与 vs2017 .net 核心 angular 模板一起使用。到目前为止没有运气。

请看Demo-Gif: Demo Gif

编辑 2018 年 4 月 12 日

现在一切正常,感谢 trimox!您可以 clone/download 来自 vs2017-Angluar-Template-with-mdc-web

的解决方案

根据以下入门教程: Angular MDC - Getting started

我知道,以下步骤会破坏 bootstrap 东西。但我只是想让按钮起作用。

问题是:如何让 angular-mdc-web 与 vs2017 Angular-Template 一起工作? 感谢您的帮助!

我是这样设置的: VS2017 社区版 15.6.4

  1. 菜单File\New\Project...
  2. ASP.NET 核心 Web 应用程序
  3. Select Angular

  4. 编辑package.json(准备angular5 with vs2017,没有bootstrap)

{
  "name": "WebApplication2",
  "private": true,
  "version": "0.0.1",
  "scripts": {
    "test": "karma start ClientApp/test/karma.conf.js",
    "build:vd": "webpack --config webpack.config.vendor.js",
    "build:cl": "webpack --config webpack.config.js",
    "build:dev": "webpack --progress --color",
    "build:aot": "webpack --env.aot --env.client & webpack --env.aot --env.server"
  },
  "dependencies": {
    "@angular/animations": "^5.2.9",
    "@angular/common": "^5.2.9",
    "@angular/compiler": "^5.2.9",
    "@angular/compiler-cli": "^5.2.9",
    "@angular/core": "^5.2.9",
    "@angular/forms": "^5.2.9",
    "@angular/http": "^5.2.9",
    "@angular/platform-browser": "^5.2.9",
    "@angular/platform-browser-dynamic": "^5.2.9",
    "@angular/platform-server": "^5.2.9",
    "@angular/router": "^5.2.9",
    "@angular-mdc/web": "^0.34.1",
    "es6-shim": "0.35.3",
    "event-source-polyfill": "0.0.12",
    "isomorphic-fetch": "2.2.1",
    "jquery": "^3.3.1",
    "preboot": "6.0.0-beta.3",
    "reflect-metadata": "0.1.12",
    "rxjs": "^5.5.8",
    "zone.js": "^0.8.21"
  },
  "devDependencies": {
    "@ngtools/webpack": "^1.10.2",
    "@types/chai": "^4.1.2",
    "@types/jasmine": "^2.8.6",
    "@types/webpack-env": "~1.13.5",
    "angular2-router-loader": "0.3.5",
    "angular2-template-loader": "0.6.2",
    "aspnet-prerendering": "^3.0.1",
    "aspnet-webpack": "^2.0.3",
    "awesome-typescript-loader": "4.0.1",
    "chai": "^4.1.2",
    "clean-webpack-plugin": "^0.1.19",
    "css": "^2.2.1",
    "css-loader": "0.28.11",
    "expose-loader": "0.7.5",
    "extract-loader": "^2.0.1",
    "extract-text-webpack-plugin": "3.0.2",
    "file-loader": "1.1.11",
    "html-loader": "0.5.5",
    "jasmine-core": "^3.1.0",
    "json-loader": "0.5.7",
    "karma": "^2.0.0",
    "karma-chai": "^0.1.0",
    "karma-chrome-launcher": "2.2.0",
    "karma-cli": "^1.0.1",
    "karma-jasmine": "^1.1.1",
    "karma-webpack": "^2.0.9",
    "loader-utils": "^1.1.0",
    "node-sass": "^4.8.3",
    "raw-loader": "0.5.1",
    "sass-loader": "^6.0.7",
    "style-loader": "0.20.3",
    "to-string-loader": "1.1.5",
    "typescript": "2.7.2",
    "url-loader": "1.0.1",
    "webpack": "^3.10.0",
    "webpack-hot-middleware": "^2.21.2",
    "webpack-merge": "^4.1.2"
  }
}
  1. 编辑webpack.config.vendor.js
...
const nonTreeShakableModules = [
    '@angular-mdc/web',                         // add this line
//    'bootstrap',                              // remove this line
//    'bootstrap/dist/css/bootstrap.css',       // remove this line
    'es6-promise',
    'es6-shim',
    'event-source-polyfill',
    'jquery',
];
...

...
const sharedConfig = {
    stats: { modules: false },
    resolve: { extensions: ['.js'] },
    module: {
        rules: [
            { test: /\.(png|woff|woff2|eot|ttf|svg)(\?|$)/, use: 'url-loader?limit=100000' }
        ]
    },
    output: {
        publicPath: 'dist/',
        filename: '[name].js',
        library: '[name]_[hash]'
    },
    plugins: [
        new CleanWebpackPlugin([path.join(__dirname, 'ClientApp', 'dist'), path.join(__dirname, 'wwwroot', 'dist')]), // add this line
        new webpack.ProvidePlugin({ $: 'jquery', jQuery: 'jquery' }), // Maps these identifiers to the jQuery package (because Bootstrap expects it to be a global variable)
        new webpack.ContextReplacementPlugin(/\@angular\b.*\b(bundles|linker)/, path.join(__dirname, './ClientApp')), // Workaround for https://github.com/angular/angular/issues/11580
        // new webpack.ContextReplacementPlugin(/angular(\|\/)core(\|\/)@angular/, path.join(__dirname, './ClientApp')), // deactivate this line
        new webpack.ContextReplacementPlugin(/\@angular(\|\/)core(\|\/)esm5/, path.join(__dirname, './ClientApp')), // add this line
        new webpack.IgnorePlugin(/^vertx$/) // Workaround for https://github.com/stefanpenner/es6-promise/issues/100
    ]
};
...
  1. 编辑webpack.config.js
...
const merge = require('webpack-merge');
// const AotPlugin = require('@ngtools/webpack').AotPlugin; // remove this line
const AngularCompilerPlugin = require('@ngtools/webpack').AngularCompilerPlugin; // add this line
const CheckerPlugin = require('awesome-typescript-loader').CheckerPlugin;
...

...
    const sharedConfig = {
        stats: { modules: false },
        context: __dirname,
        resolve: { extensions: [ '.js', '.ts' ] },
        output: {
            filename: '[name].js',
            publicPath: 'dist/' // Webpack dev middleware, if enabled, handles requests for this URL prefix
        },
        module: {
            rules: [
                { test: /\.ts$/, include: /ClientApp/, use: isDevBuild ? ['awesome-typescript-loader?silent=true', 'angular2-template-loader'] : '@ngtools/webpack' },
                { test: /\.html$/, use: 'html-loader?minimize=false' },
                { test: /\.css$/, use: ['to-string-loader', isDevBuild ? 'css-loader' : 'css-loader?minimize'] },
                // add scss loader
                {
                    test: /\.scss$/,
                    use: [
                        {
                            loader: 'file-loader',
                            options: {
                                name: 'bundle.css',
                            },
                        },
                        { loader: 'extract-loader' },
                        { loader: 'css-loader' },
                        { loader: 'sass-loader' },
                    ]
                },
                { test: /\.(png|jpg|jpeg|gif|svg)$/, use: 'url-loader?limit=25000' }
            ]
        },
        plugins: [new CheckerPlugin()]
    };
...

...
            // Plugins that apply in production builds only
            new webpack.optimize.UglifyJsPlugin(),
            new AngularCompilerPlugin({                                     // replace AotPlugin with AngularCompilerPlugin
                tsConfigPath: './tsconfig.json',
                entryModule: path.join(__dirname, 'ClientApp/app/app.browser.module#AppModule'),
                exclude: ['./**/*.server.ts']
            })
...

...
        ].concat(isDevBuild ? [] : [
            // Plugins that apply in production builds only
            new AngularCompilerPlugin({                                     // replace AotPlugin with AngularCompilerPlugin
                tsConfigPath: './tsconfig.json',
                entryModule: path.join(__dirname, 'ClientApp/app/app.server.module#AppModule'),
                exclude: ['./**/*.browser.ts']
            })
        ]),
...
  1. 编辑 tsconfig.json for typescript >=2.7.2
...

    "emitDecoratorMetadata": true,
    "strictPropertyInitialization": false, // add this line
    "skipDefaultLibCheck": true,
...
  1. 用这一行
  2. 创建ClientApp\styles.scss
@import "~@angular-mdc/theme";      // Add this line
  1. 编辑ClientApp/boot.browser.ts
...
import 'reflect-metadata';
import 'zone.js';
//import 'bootstrap';   // deactivate this line
import './styles.scss'; // add this line
...
  1. 编辑ClientApp/boot.server.ts
...
return platformDynamicServer(providers).bootstrapModule(AppModule).then(moduleRef => {
    const appRef: ApplicationRef = moduleRef.injector.get(ApplicationRef);
    const state = moduleRef.injector.get(PlatformState);
    //const zone = moduleRef.injector.get(NgZone);              // deactivated this line
    const zone: NgZone = moduleRef.injector.get(NgZone);        // add this line

    return new Promise<RenderResult>((resolve, reject) => {

...
  1. 创建ClientApp\app\app.module.mdc.ts
import { NgModule } from '@angular/core';
import {
  MdcAppBarModule,
  MdcButtonModule,
  MdcCardModule,
  MdcCheckboxModule,
  MdcChipsModule,
  MdcDialogModule,
  MdcDrawerModule,
  MdcElevationModule,
  MdcFabModule,
  MdcFormFieldModule,
  MdcGridListModule,
  MdcIconModule,
  MdcIconToggleModule,
  MdcLinearProgressModule,
  MdcListModule,
  MdcMenuModule,
  MdcRadioModule,
  MdcRippleModule,
  MdcSelectModule,
  MdcSliderModule,
  MdcSnackbarModule,
  MdcSwitchModule,
  MdcTabModule,
  MdcTextFieldModule,
  MdcThemeModule,
  MdcToolbarModule,
  MdcTypographyModule,
} from '@angular-mdc/web';

@NgModule({
  exports: [
    MdcAppBarModule,
    MdcButtonModule,
    MdcCardModule,
    MdcCheckboxModule,
    MdcChipsModule,
    MdcDialogModule,
    MdcDrawerModule,
    MdcElevationModule,
    MdcFabModule,
    MdcFormFieldModule,
    MdcGridListModule,
    MdcIconModule,
    MdcIconToggleModule,
    MdcLinearProgressModule,
    MdcListModule,
    MdcMenuModule,
    MdcRadioModule,
    MdcRippleModule,
    MdcSelectModule,
    MdcSliderModule,
    MdcSnackbarModule,
    MdcSwitchModule,
    MdcTabModule,
    MdcTextFieldModule,
    MdcThemeModule,
    MdcToolbarModule,
    MdcTypographyModule,
  ]
})
export class MdcMaterialModule { }
  1. 编辑app.shared.module.ts
...
import { RouterModule } from '@angular/router';

import { MdcMaterialModule } from './app.module.mdc'; // Add this line

import { AppComponent } from './components/app/app.component';
...

并导入它:

...
    imports: [
        CommonModule,
        HttpModule,
        FormsModule,
        MdcMaterialModule, // Add this line
        RouterModule.forRoot([
            { path: '', redirectTo: 'home', pathMatch: 'full' },
            { path: 'home', component: HomeComponent },
            { path: 'counter', component: CounterComponent },
            { path: 'fetch-data', component: FetchDataComponent },
            { path: '**', redirectTo: 'home' }
        ])
    ]
...
  1. 编辑ClientApp\app\components\app\app.component.html
<div class='container-fluid'>
    <div class='row'>
        <div class='col-sm-3'>
            <nav-menu></nav-menu>
        </div>
        <div class='col-sm-9 body-content'>
            <router-outlet></router-outlet>
        </div>
    </div>
    <!--Add this <a> Tag part-->
    <a mdc-button [primary]="true" [raised]="true">
        <i class="material-icons mdc-button__icon">add box</i>
        mdc Button
    </a>
    <!-- until here -->
</div>
  1. Clear/Empty/Delete ClientApp\app\components\navmenu\navmenu.component.html中的所有内容 这会导致在调整浏览器大小时按钮出现故障-window

  2. 编辑Views\Shared\_Layout.cshtml

...
    <base href="~/" />

    <!-- add this 2 lines -->
    <link href="https://fonts.googleapis.com/css?family=Roboto:300,300i,400,400i,500,500i,700,700i" rel="stylesheet">
    <link href="https://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet">

    <!-- deactivated this line -->
    @*<link rel="stylesheet" href="~/dist/vendor.css" asp-append-version="true" />*@

    <!-- add this line -->
    <link rel="stylesheet" href="~/dist/bundle.css" asp-append-version="true" />
...
  1. 编辑Views\Home\Index.cshtml
@{
    ViewData["Title"] = "Home Page";
}

<!-- deactivate this lines -->

@*<app asp-prerender-module="ClientApp/dist/main-server">Loading...</app>

    <script src="~/dist/vendor.js" asp-append-version="true"></script>
    @section scripts {
        <script src="~/dist/main-client.js" asp-append-version="true"></script>
    }*@

<!-- add this lines -->

<app>Loading...</app>

@section scripts {
    <script src="~/dist/vendor.js" asp-append-version="true"></script>
    <script src="~/dist/main-client.js" asp-append-version="true"></script>
}
  1. 保存所有文件并关闭 VS2017
  2. 打开Node.js命令提示符并转到项目目录(package.json所在的位置)
  3. rmdir /S node_modules(重复直到删除所有内容)
  4. npm 安装
  5. npm 运行 build:vd
  6. npm 运行 build:dev
  7. 打开VS2017和项目
  8. 等到 npm restore(select npm 输出)完成

  9. 启动解决方案 (F5) 并单击按钮

解决波纹不透明度问题的几个选项。将 node-sass 降级到 4.7.2,或升级 angular-mdc/web 到最新的 v0.34.1。

问题与波纹混合中的变量没有得到正确的插值有关。

希望对您有所帮助。