使用的angularcli为1.7.3版本
ng new cloud --routing --style scss --skip-install
在package.json的"devDependencies"
中增加
"@angular/cdk": "5.2.0", // 在安装前加上这行
"date-fns": "^1.29.0", // 可以在报错的时候再行安装
npm i
安装完成后,通过npm start
启动项目,查看是否运行正常!
添加antd的文件:
github中搜索ng-zorro-antd,查看releases,找到对应的版本(angular对应的antd的版本)
请注意: 由于 @angular/cli 的最新版本已经默认采用 angular 6.0 以上的版本,所以请使用 @angular/cli 1.7.4 及以下版本。
注意:antd:
1.x (支持 Angular 6.x & Ant Design 3.x) 即将放出
0.7.x (support Angular 5.x & Ant Design 3.x) 目前推荐版本
0.6.x (support Angular 5.x & Ant Design 2.x) 不再维护
我使用的是0.7.0版本的antd,下载后解压,components中就是对应的源码(我们可能会修改源码,所以放到了项目中)
放在app目录下,文件名字为ngdesign
antd最后会export一个模块:NgZorroAntdModule
注意.forRoot()
在app.module中引入该模块NgZorroAntdModule.forRoot();
重新编译
报错:
1.缺少date-fns,需要下载该依赖包
2.在ngdesign的组件中demo文件缺少ng-zorro-antd模块
npm install date-fns --save
删除demo文件(项目中没用)
npm WARN @angular/cdk@5.0.1 requires a peer of @angular/core@~5.1.0 but none is installed. You must install peer dependencies yourself.
npm WARN @angular/cdk@5.0.1 requires a peer of @angular/common@~5.1.0 but none is installed. You must install peer dependencies yourself.
===>说明cdk不能使用5.0.1的版本!(npm install 完成后需要看一下有什么需要注意的地方!!!)
ng2:https://www.cnblogs.com/RainingNight/p/getting-started-in-angular.html
修改了angular-cli.json文件,需要重新编译,要不然不会执行
在这里增加了antd的less文件,引入antd的样式
"styles": [
"styles.scss",
"app/ngdesign/ng-zorro-antd.less"
],
其中:app开头,不用../src等
选用的cdk为5.2.0
app.module中:NgZorroAntdModule.forRoot()
在main.ts中:
if生产环境:
window.console.log=function(){};
window.console.info=function(){};
window.console.warn=function(){};
window.console.error=function(){};
window.console.debug=function(){};
这些函数不执行
在index.html中:
<app-root></app-root>
就是app.component.ts的selector
app.routing文件:内部文件注释,改为:
export const routes: Routes = [
{path: '', redirectTo: 'auth', pathMatch: 'full'},
{path: '**', redirectTo: 'auth'},
];
export const routing: ModuleWithProviders = RouterModule.forRoot(routes, {useHash: false});
app.module中引入routing(imports)
新建pages模块:
代码丢失,补上
ng g module pages --routing -d
ng g c pages --view-encapsulation None
新建auth模块:
ng g m pages/auth --routing
ng g c pages/auth --view-encapsulation None
新建auth内部组件:
ng g c pages/auth/components/login --view-encapsulation None
新建设备管理模块:
ng g m pages/device-mgmt --routing
ng g c pages/device-mgmt --view-encapsulation None
新建device-mgmt内部组件页面:
ng g c pages/device-mgmt/components/overview --view-encapsulation None
模块不会自动加载在模块中,所以在app.module中依赖pages.module
重新routing文件,并在module中引入routing:
pages.routing:
export const routes: Routes = [
{
path: 'auth',
loadChildren: 'app/pages/auth/auth.module#AuthModule'
},
{
path: 'pages',
component: PagesComponent,
children: [
{path: '', redirectTo: 'device-mgmt', pathMatch: 'full'},
{
path: 'device-mgmt',
loadChildren: 'app/pages/device-mgmt/device-mgmt.module#DeviceMgmtModule'
}
]
}
];
export const routing: ModuleWithProviders = RouterModule.forRoot(routes);
auth.routing:
export const routes: Routes = [
{
path: '',
component: AuthComponent,
children: [
{path: '', redirectTo: 'login', pathMatch: 'full'},
{path: 'login', component: LoginComponent}
]
}
];
export const routing: ModuleWithProviders = RouterModule.forChild(routes);
device-mgmt.routing:
export const routes: Routes = [
{
path: '',
component: DeviceMgmtComponent,
children: [
{path: '', redirectTo: 'overview', pathMatch: 'full'},
{path: 'overview', component: OverviewComponent}
]
}
];
export const routing: ModuleWithProviders = RouterModule.forChild(routes);
重写html文件:
app.html,pages.html,auth.html,device-mgmt.html:
<router-outlet></router-outlet>
注意:错误提示:Error: Component AuthComponent is not part of any NgModule or the module has not been imported into your module.
我的错误是因为:我本地有两个项目,在加载模块的时候,默认加载的是另外一个项目的路径!应该加载自己本项目的文件的路径!
eg:
import {PagesComponent} from "./pages.component"; // 正确的
// import {PagesComponent} from "../../../../cloud/src/app/pages/pages.component"; // 错误的
安装jquery和bootstrap(实际上我们只用bs就够了)
安装bootstrap地址
npm install bootstrap --save
npm install @types/bootstrap --save-dev
安装normalize.css
npm install --save normalize.css
styles.scss中:
@import "../node_modules/normalize.css/normalize.css";
@import "../node_modules/bootstrap/scss/bootstrap.scss";
angular-cli.json中styles:
"app/theme/theme.scss",
"styles.scss",
"app/ngdesign/ng-zorro-antd.less"
注意错误分析:
[WDS] Errors while compiling. Reload prevented.
Cannot read property ‘replace’ of null
或者:
ERROR Error: Uncaught (in promise): TypeError: webpack_require.e is not a function
TypeError: webpack_require.e is not a function
at webpackAsyncContext (eval at ./src/$$_lazy_route_resource lazy recursive (main.bundle.js:13), :15:29)
路由写错字了,改正确后需要重新编译,要不然就是第二种错误!!!!
login页面中:外盒子auto,内盒子hidden
.login-container {
width: 100%;
height: 100%;
min-height: 700px;
overflow: auto;
.login{
width: 100%;
height: 100%;
overflow: hidden;
background: #F2FBFF;
position: relative;
footer用fixed就可以了!
把form表单复制进来,需要导入formModule的
app.module
BrowserAnimationsModule,
BrowserModule,
HttpModule,
RouterModule,
FormsModule,
ReactiveFormsModule,
NgaModule.forRoot(),
NgZorroAntdModule.forRoot({extraFontName:'anticon',extraFontUrl:'../assets/iconfont/iconfont'}),
PagesModule,
routing
auth.module,device-mgmt.module:
CommonModule,
FormsModule,
ReactiveFormsModule,
AppTranslationModule,
NgaModule,
NgZorroAntdModule,
routing
antd中form表单拿过来使用,此时需要接口了
用base.service和模块的service
environment.ts中:
export const environment = {
production: false,
getServer: function () {
return '';
}
};
new Headers();
错误:
src/app/pages/base-service.ts(26,42): error TS2345: Argument of type ‘{ search: any; headers: Headers; }’ is not assignable to parameter of type ‘RequestOptionsArgs’.
import { Headers} from ‘@angular/http’; // 增加这个!
错误提示:
ERROR Error: StaticInjectorError(AppModule)[AuthService -> HttpClient]:
StaticInjectorError(Platform: core)[AuthService -> HttpClient]:
NullInjectorError: No provider for HttpClient!
因为:在baseService中使用了HttpClient,所以需要在app.module中用:HttpClientModule
新建了base-service和auth.service的文件
需要代理:增加:proxy.json文件
{
"/auth": {
"target": "http://xxxxxxx.com",
"secure": false,
"changeOrigin": true,
"pathRewrite": {
"^/auth": "/auth"
}
}
}
package.json中:修改:
"start": "ng serve --proxy-config proxy.conf.json",
字体图标没有生效,如何配置????
成功res返回数据结构:
res对象格式:
其中:
headers:是let myHeader: Headers = new Headers();这种格式,在使用headers.toJSON()后,是map格式!
只能使用toJSON()方法!JSON.parse()或者.json()是错误的!!!!
headers:Headers {_headers: Map(13), _normalizedNames: Map(13)}
ok:true
status:200
statusText:"OK"
type:2
url:"http://localhost:4200/auth/verify-token"
_body:"{↵ "transit" : false↵}"
其中:_headers:
_headers
:
Map(13) {"pragma" => Array(1), "date" => Array(1), "x-content-type-options" => Array(1), "server" => Array(1), "x-powered-by" => Array(1), …}
map对象格式
在项目中使用base64:
方法1:
base64的使用方法
方法2:
app/widget/script下,放入base64.js
import '../widget/script/base64.js';
declare var Base64: any;
new Base64().encode('dankogai'); //使用:
3des的使用:
npm i crypto-js // 安装
import * as CryptoJS from 'crypto-js'; // 使用
使用AppCommon:
widget/script/sessionStorage.ts
export class session{
static set(key:string, value:any) {
sessionStorage.setItem(key, JSON.stringify(value));
}
static get(key:string) {
var d = sessionStorage.getItem(key);
if (!d) return d;
return !!d?JSON.parse(d):"";
}
static remove(key:string) {
sessionStorage.removeItem(key);
}
static clear() {
sessionStorage.clear();
}
//如果设置为length,转为js时会报错
static count(){
return sessionStorage.length;
}
}
app-common.ts
import { session } from '../widget/script/sessionStorage';
export class AppCommon{
// 租户
private static _tenants;
// 获取租户信息
static get tenants() {
if (!this._tenants) {
this._tenants = session.get("_tenants");
}
return this._tenants
}
// 设置租户信息
static set tenants(value) {
this._tenants = value;
session.set("_tenants", value);
}
}
在每个模块中都需要引入antd!
登录成功后调用一系列接口,同时在session中存储信息
菜单部分:
html写死数据是么有问题的,但是菜单单独出来后,在收回状态时有问题的!
菜单一级和二级的问题解决了:
<div>
<ul nz-menu [nzTheme]="'dark'" [nzMode]="'inline'"
[nzInlineCollapsed]="isCollapsed">
<div *ngFor="let item1 of menus">
<li *ngIf="item1.isLeaf=='0'" nz-submenu>
<span title>
<i
class="anticon {{item1.iconClass}}"></i>
<span>{{item1.nameCn}}</span>
</span>
<ul>
<li nz-menu-item *ngFor="let item2 of item1.children"
[routerLink]="[item2.url]"
routerLinkActive="active">
{{item2.nameCn}}
</li>
</ul>
</li>
<li *ngIf="item1.isLeaf!='0'" nz-menu-item
[routerLink]="[item1.url]"
routerLinkActive="active">
<span title>
<i class="anticon {{item1.iconClass}}"></i>
<span>{{item1.nameCn}}</span>
</span>
</li>
</div>
</ul>
</div>
在li外面套一层div,循环,那么nz-submenu或者nz-menu-item可以使用了!
ts:
public menus = [
{
isLeaf: '0',
level: 1,
nameCn: '设备1',
iconClass: 'anticon-api',
children: [
{
isLeaf: '1',
level: 2,
nameCn: '概览',
url: '/pages/device-mgmt/overview'
},
{
isLeaf: '1',
level: 2,
nameCn: '趋势',
url: '/pages/device-mgmt/trend'
},
{
isLeaf: '1',
level: 2,
nameCn: '日志',
url: '/pages/device-mgmt/log'
},
]
},
{
isLeaf: '0',
level: 1,
nameCn: '团队',
iconClass: 'anticon-usergroup-delete',
children: [
{
isLeaf: '1',
level: 2,
nameCn: '团队1',
url: '/pages/device-mgmt/team1'
},
{
isLeaf: '0',
level: 2,
nameCn: '团队2',
iconClass: 'anticon-user',
url: '/pages/device-mgmt/team2',
/*children: [
{
isLeaf: '1',
level: 3,
nameCn: '团队2-a',
url: '/pages/device-mgmt/team2-a'
},
{
isLeaf: '1',
level: 3,
nameCn: '团队2-b',
url: '/pages/device-mgmt/team2-b'
}
]*/
}
]
},
{
aliasName: '用户',
isLeaf: '1',
level: 1,
nameCn: '用户',
iconClass: 'anticon-android-o',
url: '/pages/device-mgmt/user'
}
];
菜单没有正常显示样式问题分析:
1.是否折叠别用nzTrigger了,自己用isCollapsed来传递!
2.上面我用了div包裹了一层,所以默认样式中用子类选择器无效,修改源码:
在:src/app/ngdesign/menu/style/index.less
&-inline-collapsed {
width: @menu-collapsed-width;
> .@{menu-prefix-cls}-item,
> .@{menu-prefix-cls}-item-group > .@{menu-prefix-cls}-item-group-list > .@{menu-prefix-cls}-item,
> .@{menu-prefix-cls}-submenu > .@{menu-prefix-cls}-submenu-title {
这些子类选择器修改为后代选择器!
3.修改菜单的w:
在src/app/ngdesign/style/themes/default.less中:
@menu-collapsed-width: 64px; // 折叠后菜单的w,自动可以居中,计算css值了的
且需要:
src/app/ngdesign/layout/nz-sider.component.ts
@Input() nzWidth = 200;
@Input() nzCollapsedWidth = 80; // 修改值
左上角图片:
.logo:overflow:hidden,要不然图片会换行!
[ngClass]="{'marginleft5':isCollapsed}" // 要不然折叠时候,小图片没有居中
最终:pages.html:
<div class="page-container">
<nz-layout style="height: 100%;">
<!--左边栏-菜单-->
<nz-sider nzCollapsible [(nzCollapsed)]="isCollapsed"
[nzTrigger]="null" >
<div class="logo">
<img [ngClass]="{'marginleft15':isCollapsed}" src="../../assets/images/basic/xxx.png" alt=""><img *ngIf="!isCollapsed" src="../../assets/images/basic/xxx.png" alt="">
</div>
<app-ks-page-menu [isCollapsed]="isCollapsed"></app-ks-page-menu>
</nz-sider>
<!--右侧部分-->
<nz-layout style="height: 100%;">
<!--折叠按钮-->
<nz-header style="background: #fff; padding:0;">
<i class="anticon trigger" [class.anticon-menu-fold]="!isCollapsed"
[class.anticon-menu-unfold]="isCollapsed"
(click)="collapseFuc();"></i>
</nz-header>
<nz-content style="margin:0 16px;height: calc(100% - 133px);">
<nz-breadcrumb style="margin:16px 0;">
<nz-breadcrumb-item>User</nz-breadcrumb-item>
<nz-breadcrumb-item>Bill</nz-breadcrumb-item>
</nz-breadcrumb>
<div style="padding:24px; background: #fff; min-height: 360px;height: 100%;">
<router-outlet></router-outlet>
</div>
</nz-content>
<nz-footer style="text-align: center;">Ant Design ©2017 Implement By Angular
</nz-footer>
</nz-layout>
</nz-layout>
</div>
pages.scss
.page-container {
height: 100%;
// 菜单折叠按钮 样式
.trigger {
font-size: 28px;
line-height: 64px;
padding: 0 24px;
cursor: pointer;
transition: color .3s;
}
.trigger:hover {
color: #1890ff;
}
.logo {
height: 64px;
overflow: hidden;
margin-top: 7px;
.marginleft15 {
margin-left: 15px;
}
}
}
page-menu.html:
<ul nz-menu [nzTheme]="'dark'" [nzMode]="'inline'"
[nzInlineCollapsed]="isCollapsed">
<div *ngFor="let item1 of menus">
<li *ngIf="item1.isLeaf=='0'" nz-submenu>
<span title>
<i
class="anticon {{item1.iconClass}}"></i>
<span>{{item1.nameCn}}</span>
</span>
<ul>
<li nz-menu-item *ngFor="let item2 of item1.children"
[routerLink]="[item2.url]"
routerLinkActive="active">
{{item2.nameCn}}
</li>
</ul>
</li>
<li *ngIf="item1.isLeaf!='0'" nz-menu-item
[routerLink]="[item1.url]"
routerLinkActive="active">
<span title>
<i class="anticon {{item1.iconClass}}"></i>
<span>{{item1.nameCn}}</span>
</span>
</li>
</div>
</ul>
html默认字体14px,不是我们想要的:
src/app/ngdesign/style/themes/default.less
@font-size-base : 14px; // 修改!
在page中:
padding和margin去掉,我们在自己的 页面要写面包屑的!
pages.html:
<div class="page-container">
<nz-layout style="height: 100%;overflow: hidden;">
<!--左边栏-菜单-->
<nz-sider nzCollapsible [(nzCollapsed)]="isCollapsed"
[nzTrigger]="null" >
<div class="logo">
<img [ngClass]="{'marginleft15':isCollapsed}" src="../../assets/images/basic/new-logo-close.png" alt=""><img *ngIf="!isCollapsed" src="../../assets/images/basic/new-logo-open.png" alt="">
</div>
<app-ks-page-menu [isCollapsed]="isCollapsed"></app-ks-page-menu>
</nz-sider>
<!--右侧部分-->
<nz-layout style="height: 100%;overflow: hidden;">
<!--折叠按钮-->
<nz-header style="background: #fff; padding:0;border-bottom: 1px solid #D8D8D8; ">
<i class="anticon trigger" [class.anticon-menu-fold]="!isCollapsed"
[class.anticon-menu-unfold]="isCollapsed"
(click)="collapseFuc();"></i>
</nz-header>
<nz-content style="margin:0;height: 100%;overflow-y: auto;">
<div style="height: 100%;">
<router-outlet></router-outlet>
</div>
</nz-content>
<nz-footer style="text-align: center;z-index: 1;">Ant Design ©2017 Implement By Angular
</nz-footer>
</nz-layout>
</nz-layout>
</div>
pages.scss:
.page-container {
height: 100%;
// 菜单折叠按钮 样式
.trigger {
font-size: 28px;
line-height: 64px;
padding: 0 24px;
cursor: pointer;
transition: color .3s;
}
.trigger:hover {
color: #1890ff;
}
.logo {
height: 64px;
overflow: hidden;
margin-top: 7px;
.marginleft15 {
margin-left: 15px;
}
}
}
overview.html:
<div class="overview-container">
<div class="overview">
<!----------面包屑 开始------------>
<nz-breadcrumb>
<nz-breadcrumb-item>
一级菜单
</nz-breadcrumb-item>
<nz-breadcrumb-item>
<a>二级菜单</a>
</nz-breadcrumb-item>
</nz-breadcrumb>
<!-----------面包屑 结束------------>
<div class="content-box">
<div class="search-container">
<div nz-row>
<div nz-col [nzSpan]="6">
<div nz-row class="ks-item">
<div nz-col [nzSpan]="8" class="ks-label">
label标签:
</div>
<div nz-col [nzSpan]="16" class="ks-form">
<nz-select style="width: 100%;"></nz-select>
</div>
</div>
</div>
<div nz-col [nzSpan]="6">
<div nz-row class="ks-item">
<div nz-col [nzSpan]="8" class="ks-label">
label标签2:
</div>
<div nz-col [nzSpan]="16" class="ks-form">
<!--<nz-input [(ngModel)]="abc" placeholder="'请输入'"></nz-input>-->
<input [(ngModel)]="abc" placeholder="请输入" nz-input>
</div>
</div>
</div>
<!--查询和重置-->
<div nz-col [nzSpan]="6">
<div nz-row class="ks-item">
<button nz-button [nzType]="'primary'" class="search-btn"
(click)="search(true);">
<span>搜索</span>
</button>
<button nz-button [nzType]="'default'" class="reset-btn"
(click)="reset();">
<span>重置</span>
</button>
</div>
</div>
</div>
</div>
<div class="table-container">
<nz-table #basicTable [nzData]="dataSet">
<thead>
<tr>
<th>Name</th>
<th>Age</th>
<th>Address</th>
<th>Action</th>
</tr>
</thead>
<tbody>
<tr *ngFor="let data of basicTable.data">
<td>{{data.name}}</td>
<td>{{data.age}}</td>
<td>{{data.address}}</td>
<td>
<a>Action 一 {{data.name}}</a>
<nz-divider nzType="vertical"></nz-divider>
<a>Delete</a>
</td>
</tr>
</tbody>
</nz-table>
</div>
</div>
</div>
</div>
overview.scss:
.overview-container{
width: 100%;
height: 100%;
.overview{
width: 100%;
height: 100%;
.ant-breadcrumb {
height: 40px;
line-height: 40px;
background: #fff;
padding-left: 20px;
// 面包屑的每一项
.ant-breadcrumb-link {
color: blue;
}
// 面包屑的“/”分隔符
.ant-breadcrumb-separator {
color: blue;
}
// 最后一项 item里面的 改变样式,注意自己调试的样式bug问题
//.ant-breadcrumb-link:last-of-type{
nz-breadcrumb-item:last-child {
// 在获取到标签,再取里面的类
.ant-breadcrumb-link {
font-weight: normal;
color: red;
}
}
}
.content-box{
padding: 20px;
.search-container{
padding: 20px 20px 0 0;
background: #fff;
// 多选select的h,多了后滚动
.ant-select-selection--multiple {
height: 32px;
overflow: auto;
}
.ks-item {
margin-bottom: 20px;
.ks-label {
height: 32px; // 行高32px
line-height: 32px;
text-align: right;
font-size: 12px;
color: rgba(0, 0, 0, 0.85);
}
.ks-form {
.ant-input { // input的样式设置
height: 32px;
}
.ant-select-selection__rendered { // 多选select的样式
height: 30px;
line-height: 30px;
}
.ant-select-selection--multiple > ul > li, // 多选select的样式
.ant-select-selection--multiple .ant-select-selection__rendered > ul > li {
height: 24px;
line-height: 24px;
}
.ant-select-selection--single { // 单选 select的样式
height: 32px;
}
}
}
.search-btn { // 搜索按钮
width: 67px;
height: 30px;
margin-top: 1px;
margin-left: 15px;
}
.reset-btn { // 重置按钮
width: 67px;
height: 30px;
margin-top: 1px;
margin-left: 5px;
}
}
.table-container{
margin-top: 8px;
padding: 0 20px 20px;
background: #fff;
color: #222;
}
}
}
}
此时:菜单还没有滚动条:
给菜单的url加上:
height: calc(100% - 64px);
overflow: auto;
style.scss:
// 左右中的对齐方式
.tac {
text-align: center;
}
.tal {
text-align: left;
}
.tar {
text-align: right;
}
// cursorpointer的样式
.cursor-pointer {
cursor: pointer;
}
// textarea不可以缩放
textarea {
resize: none;
}
// form表单:必填项的*的颜色
.color-require {
font-size: 14px;
color: rgba(255, 0, 0, 0.85);
vertical-align: middle;
}
:focus {
outline: none;
}
.hyper-link {
cursor: pointer;
color: #2D9AFF;
}
.hyper-link:hover {
color: #0973D6;
}
// "..."的样式,用类表示; 配合w来使用=》可以使用百分比
.ellipsis {
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}