初始化环境
npm install -g @angular/cli
ng new ngapp
ng serve --open
ng serve --proxy-config proxy.conf.json --host 0.0.0.0 --disable-host-check --port 4200 --live-reload-port 4201
ng serve --prod --env=dev --proxy-config proxy.conf.json --host 0.0.0.0 --disable-host-check
ng build --target=production --environment=prod
ng build --prod --env=prod
ng build --prod
ng build --target=development --environment=dev
ng build --dev --e=dev
ng build --dev
常用开发命令-组件、服务、路由
ng generate component heroes
ng generate component hero -it
ng g c --inline-template=true --inline-style=true tab
ng generate service hero
ng generate service hero --module=app
ng generate module app-routing --flat --module=app
ng generate class hero
页面常用指令
{{ hero.name | uppercase }}
{{nullHero?.name}}
{{$any(hero).marker}}
(click)="onSelect(hero)"
<a routerLink="/heroes">H</a>
[(ngModel)]="hero.name"
[ngClass]="currentClasses"
[class.special]="isSpecial"
[ngStyle]="currentStyles"
[style.display]="isSpecial ? 'block' : 'none'"
[style.visibility]="isFirstVote?'visible':'hidden'"
[innerHTML]="aa"
*ngFor="let hero of heroes;let i = index"
[ngSwitch]="currentHero.emotion" --> *ngSwitchCase="'happy'" --> *ngSwitchDefault
(focus)="getMatchInfo()"
<ng-content select="[ion-fixed],ion-fab"></ng-content>
<ng-container></ng-container>
<ng-template></ng-template>
Angular常用TS
@Input() hero: Hero;
@Output('myClick') clicks
@ViewChild(ChildenComponent) child: ChildenComponent;
@ViewChild("child") child2;
@ViewChild('childB', {read: ElementRef})
@ViewChild('childB', {read: ViewContainerRef})
@ViewChild("refresher") divTop: ElementRef;
<input
@ViewChild("top",{read: ElementRef}) ticketEle;
this.top && this.top.nativeElement.scrollIntoView (true);
scrollToSelect() {
let selected = this.ticketEle.nativeElement.querySelector(".select");
if(selected) {
let ofTop = selected.offsetTop;
this.scroll.nativeElement.scrollTo(0,ofTop);
}
}
elementRef.nativeElement.cloneNode(true)
element.parentNode && element.parentNode.removeChild(element);
@NgModule({ schemas: [CUSTOM_ELEMENTS_SCHEMA] })
import {Observable} from "rxjs";
Observable.fromEvent(this.ele.nativeElement, 'scroll').subscribe((event) => {
console.log('scroll',32);
});
import {Renderer2} from "@angular/core";
this.renderer.listen(this.ele.nativeElement, 'click', () => {
console.log('click',27);
});
//js阻止事件冒泡
oEvent.cancelBubble = true;
oEvent.stopPropagation();
//js阻止链接默认行为,没有停止冒泡
oEvent.preventDefault();
import {ChangeDetectorRef} from '@angular/core';
public cdf: ChangeDetectorRef
this.cdf.detectChanges();
ng g pipe service/date --module ../router/bootstrap
ng g service service/http
ES6常用语法
heroes => this.heroes = heroes
{ name } as Hero
{bbc}
arrs.find(item => item === 1)
heroes.filter(h => h !== hero)
oldArray.map(entry => {'abc:' + entry;})
/**
* 排序,false:倒序,默认从大到小
* @param {string} prop,{boolean} sc asc/desc
* @returns {any}
* this.sortArray('d30WinRatio',false);
*/
sortArray(prop: string,sc:boolean=true) {
const sorted = this.list.sort((a, b) => a[prop] > b[prop] ? 1 : a[prop] === b[prop] ? 0 : -1);
if(!sc) sorted.reverse();
return sorted;
}
let arr = Object.keys(this.typeData).map(key=> this.typeData[key]);
class C{
a;
b;
getA(){return this.a}
getB(){return this.b}
}
let tmp = new C();
let obj = {a:6,b:7};
var res = Object.assign(tmp,obj,{c:8});//{a:6,b:7,c:8}; res === tmp;
打包和优化
ng build --prod --bh ./
ng build –prod –aot
ng build --prod --stats-json
ng build --prod --build-optimizer
ng eject
Angular的Rest风格部署
location / {
root html/dist;
try_files $uri $uri/ /index.html =404;
index index.html index.htm;
}
app.use(function (req, res) {
console.log(req.path);
if(req.path.indexOf('/api')>=0){
res.send("server text");
}else{ //angular启动页
res.sendfile('app/index.html');
}
});
常用开发技巧
npm install angular-cli-tools -g
ngt g class [class-name]
ngt g c [component-name]
ngt g d [directive-name]
ngt g e [enum-name]
ngt g h [name]
ngt g index
ngt g i [interface-name]
ngt g m [module-name]
ngt g p [pipe-name]
ngt g r [route-name]
ngt g routing [routing-name]
ngt g s [service-name]e]
ngt g style [style-name]
import { NgModule } from '@angular/core';
import { Routes, RouterModule } from '@angular/router';
import { ActivityComponent } from './activity.component';
const routes: Routes = [
{ path: '', component: ActivityComponent },
];
@NgModule({
imports: [ RouterModule.forChild(routes)],
exports: [ RouterModule ]
})
export class ActivityRouting{};
/*
{path: 'activity', loadChildren: './activity/activity.module#ActivityModule'},
*/
ngt update index --recursive
ngt install config
ngt s ./login-form.module.ts -t:form-module
ngt g m test -t:form-module
ng update @angular/cli
ng g c --inline-template=true --inline-style=true tab
ng g c tab -its
route.snapshot.params['roomStatus']
route.queryParams['roomStatus']
this.router.navigate(['/activity/puzzles/ranking', {uid: 123, tid: res.model.id}])
routerLink="/activity/puzzles"
this.router.navigate(['/login'],{ skipLocationChange: true });
this.router.navigate(['./ranking'],{replaceUrl:true,relativeTo:this.currentRoute});//Url改变,不添加到历史记录
import {debounceTime, filter, map, mergeMap} from "rxjs/operators";
this.subRouter = this.router.events
.pipe(filter(event => event instanceof NavigationEnd),map(() => this.route))
.pipe(map(route => {
while (route.firstChild) route = route.firstChild;
return route;
}))
.pipe(filter(route => route.outlet === 'primary'))
.pipe(mergeMap(route => route.params),debounceTime(300))
.subscribe((event) =>{
if(Number(event.uid) && Number(event.type)){
this.uid = +event.uid;
this.type = +event.type;
}
});
if (!!(window.history && history.pushState)){
history.replaceState({uid: this.uid, type: this.type}, '活动排名页', `
}else{
//this.router.navigate(['/activity/puzzles/ranking', {uid: this.uid, type: this.type}]);
this.router.navigate(['./ranking'],{replaceUrl:true,relativeTo:this.currentRoute});//不添加到历史记录
}
//rxjs防抖动函数
import {Subject} from "rxjs/Subject";
import {debounceTime, distinctUntilChanged} from 'rxjs/operators';
changeStream: Subject<string> = new Subject<string>();
this.order = this.order ||
this.changeStream
.pipe(debounceTime(2000))
.pipe(distinctUntilChanged())
.subscribe(streetText => {
//实际业务处理
console.log(38);
});
this.changeStream.next(this.list);
常用指令写法
import { DatePipe } from '@angular/common';
private datePipe: DatePipe
this.datePipe.transform(this.ticketInfo.flyTime, 'yyyy-MM-dd HH:mm')
既不是一个Component,也不是一个Directive,只是单纯的一个特殊tag。ng-container可以直接包裹任何元素,包括文本,但本身不会生成元素标签,也不会影响页面样式和布局。包裹的内容,如果不通过其他指令控制,会直接渲染到页面中
https://map.baidu.com/?qt=cur&wd=%E6%B7%B1%E5%9C%B3%E5%B8%82 //天气预报接口
https://map.baidu.com/mobile/?qt=loc&x=113.9278992&y=22.543741&pois=1 //地理信息接口
IphoneX的样式兼容
@media only screen and (device-width: 375px) and (device-height: 812px) and (-webkit-device-pixel-ratio: 3) {
.iphoneTop .indexTop,
.iphoneTop .liveTop,
.iphoneTop .navBar{ padding-top: 44px;}
.betBottomBar,.messageFixed{ bottom: 34px;}
.iphoneTop .fixed_top_bar .title{ margin-top: 44px;}
}
.content-bg{background: url(../images/bg_repeat.jpg) repeat-y;background-size: 100% auto;}
html::-webkit-scrollBar{display:none;}
input:-webkit-autofill,
input:-webkit-autofill:hover,
input:-webkit-autofill:focus,
input:-webkit-autofill:active {
-webkit-box-shadow: 0 0 0px 1000px
transition: background-color 50000s ease-in-out 0s, color 5000s ease-in-out 0s;
}
input:-webkit-autofill {
-webkit-animation: autofill-fix 1s infinite;
}
@-webkit-keyframes autofill-fix {
from {
background-color: transparent
}
to {
background-color: transparent
}
}
.spinner{
-webkit-animation: spin 1s linear 1s 5 alternate;
animation: spin 1s linear infinite;
display: inline-block;
}
@-webkit-keyframes spin {
from {
-webkit-transform: rotate(0deg);
}
to {
-webkit-transform: rotate(360deg);
}
}
@keyframes spin {
from {
transform: rotate(0deg);
}
to {
transform: rotate(360deg);
}
}
declare var window:any;
initWinPage(){
this.restWinPage(window, window.lib || (window.lib = {}));
}
private restWinPage(N, M) {
function L() {
let a = I.getBoundingClientRect().width;
a / F > 540 && (a = 540 * F);
let d = a / 7.5;
I.style.fontSize = d + "px", D.rem = N.rem = d
}
let K, J = N.document, I = J.documentElement, H = J.querySelector('meta[name="viewport"]'),
G = J.querySelector('meta[name="flexible"]'), F = 0, E = 0, D = M.flexible || (M.flexible = {});
if (H) {
// console.warn("将根据已有的meta标签来设置缩放比例");
let C = H.getAttribute("content").match(/initial\-scale=([\d\.]+)/);
C && (E = parseFloat(C[1]), F = parseInt(''+1 / E))
} else {
if (G) {
let B = G.getAttribute("content");
if (B) {
let A = B.match(/initial\-dpr=([\d\.]+)/), z = B.match(/maximum\-dpr=([\d\.]+)/);
A && (F = parseFloat(A[1]), E = parseFloat((1 / F).toFixed(2))), z && (F = parseFloat(z[1]), E = parseFloat((1 / F).toFixed(2)))
}
}
}
if (!F && !E) {
let y = N.navigator.userAgent, x = (!!y.match(/android/gi) && !!y.match(/iphone/gi)),
w = x && !!y.match(/OS 9_3/), v = N.devicePixelRatio;
F = x ? v >= 3 && (!F || F >= 3) ? 3 : v >= 2 && (!F || F >= 2) ? 2 : 1 : 1, E = 1 / F
}
if (I.setAttribute("data-dpr", F), !H) {
if (H = J.createElement("meta"), H.setAttribute("name", "viewport"), H.setAttribute("content", "initial-scale=" + E + ", maximum-scale=" + E + ", minimum-scale=" + E + ", user-scalable=no"), I.firstElementChild) {
I.firstElementChild.appendChild(H)
} else {
let u = J.createElement("div");
u.appendChild(H), J.write(u.innerHTML)
}
}
N.addEventListener("resize", function () {
clearTimeout(K), K = setTimeout(L, 300)
}, !1), N.addEventListener("pageshow", function (b) {
b.persisted && (clearTimeout(K), K = setTimeout(L, 300))
}, !1), "complete" === J.readyState ? J.body.style.fontSize = 12 * F + "px" : J.addEventListener("DOMContentLoaded", function () {
J.body.style.fontSize = 12 * F + "px"
}, !1), L(), D.dpr = N.dpr = F, D.refreshRem = L, D.rem2px = function (d) {
let c:any = parseFloat(d) * this.rem;
return "string" == typeof d && d.match(/rem$/) && (c += "px"), c
}, D.px2rem = function (d) {
let c:any = parseFloat(d) / this.rem;
return "string" == typeof d && d.match(/px$/) && (c += "rem"), c
}
}
-webkit-transform: scaleY(0.7);//Y轴方向,缩放0.6倍
-webkit-transform-origin: 100% 100%;//缩放在右下角对齐
margin-top: -50px;//负值margin从而把其位置摆正确,有时需要放到包在div的外面
margin-left: -95px;//如果用scale全部缩放,需要设置这个值
[style.marginTop.px]="cartoonHeight*0.2*-1"
[style.marginLeft.px]="cartoonWidth*0.2*-1"
style="transform: scale(0.8);-webkit-transform: scale(0.8);-webkit-transform-origin: 100% 100%;"
SASS常用技巧
node-sass scss/app.scss css/app.css --output-style compressed
node-sass -w -r scss -o css --output-style compressed
cookie相关设置
function GetCookieDomain() {
var host = location.hostname;
var ip = /^(\d{1,2}|1\d\d|2[0-4]\d|25[0-5])\.(\d{1,2}|1\d\d|2[0-4]\d|25[0-5])\.(\d{1,2}|1\d\d|2[0-4]\d|25[0-5])\.(\d{1,2}|1\d\d|2[0-4]\d|25[0-5])$/;
if (ip.test(host) === true || host === 'localhost') return host;
var regex = /([^]*).*/;
var match = host.match(regex);
if (typeof match !== "undefined" && null !== match) host = match[1];
if (typeof host !== "undefined" && null !== host) {
var strAry = host.split(".");
if (strAry.length > 1) {
host = strAry[strAry.length - 2] + "." + strAry[strAry.length - 1];
}
}
return '.' + host;
}
document.cookie = cname + "=" + cvalue + "; expires=" + expires + "; domain=" + GetCookieDomain() + "; path=/";
expires = (new Date().getTime() - 1000);
document.cookie = "agentId" + "=" + "123" + "; expires=" + (new Date().getTime() - 1000) + "; domain=" + GetCookieDomain() + "; path=/";