使用visibility隐藏元素时,元素及其内容应该出现的位置会留下一片空白区域,仍然会在文档流中占据位置。
display: none;完全从文档中拿出。
设置元素width值,并且将左右外边距都设为auto,导致元素居中。
内边距不能继承,外边距不继承,边框不继承,float属性不继承,定位不继承,z-index不继承,overflow不继承。
边框的默认颜色是元素的color属性的值。
如果一个元素位于另一个元素的上面,对于相互接触的两个margin(即元素相互接触的下外边距和上外边距),仅使用其中较大的一个,另一个外边距会被叠加。左右外边距不叠加。
当em值用于内边距和外边距时,它的值是相对于元素的字体大小的,而不是相对于父元素的字体大小的。
浮动的元素并不会影响父元素或者其它祖先元素的高度,因此从这一点来说,它不属于文档流的一部分。
对某个元素使用clear属性,该元素和它后面的元素就会显示在浮动元素的下面。
让浮动的父元素自清除:
添加clearfix类,并添加css片段:
.clearfix:after {
content:".";
display:block;
height:0;
visibility:hidden;
clear:both;
}
应该将clear属性添加到不希望环绕浮动对象的元素上。因此,如果要让一个元素在右侧没有浮动元素之后才显示,就为它添加clear:right;。而clearfix和overflow方法是应用于浮动元素的父元素或祖先元素的。
对父元素添加overflow:hidden会强制它包围浮动元素。
背景有8个属性构成:
background:
url(sweettexture.jpg) /*image*/
top center / 200px 200px /*position*/
no-repeat /*repeat*/
fixed /*attachment
padding-box /*origin*/
content-box /*clip*/
red; /*color*/
对绝对定位元素的父元素(非body)设置position:relative,从而让绝对元素可以相对其父元素(而不是body元素)进行绝对定位,这样就可以让绝对元素显示在我们希望它显示的位置。
绝对定位和固定定位都是完全移出文档流。固定定位元素的定位上下文是视口,因此它不会随页面滚动而移动。
注意:固定定位在很多移动浏览器中效果不佳。
定位的默认设置是static。
z-index只对相对,绝对,固定定位有影响,而对static定位没有影响,static元素总是在最底层。
vertical-align只能用于表格和行内元素,不能用于块级元素。
只有HTML中不包含width和height属性,图像才有可能变成可伸缩的图像。可伸缩图像可以根据包含它们的元素的尺寸按比例缩放。但是不会比其本来的宽度更宽。使用css控制缩放,一定要使用max-width:100%而不是width:100%;。
使用background-size属性对背景图像进行缩放,这个属性是最有用,最复杂的背景属性之一,有四种不同的语法:
1. 关键字,auto(浏览器自动计算图像大小和宽高比),cover(图像覆盖背景),contain(必须显示这个图像,哪些边上有空白)。
2. 一个值,如background-size: 400px;这个指宽度,高度被置为auto。
3. 二个值,宽和高
5. 多个图像,混合上面多种方法:
html {
background: url(greatimage.jpg), url(wonderfulimage.jpg);
background-size: 300px 100px, cover;
/* 第一个图像 300x100, 第二个图像覆盖整个区域 */
}
浏览器的默认字体大小是16px。
图来自:https://segmentfault.com/a/1190000003038583
bootstrap的屏幕规格:
xs: extra small,特别小,小于576px
sm: small, 小,576px以及以上
md: 中等,768px以及以上
lg: large, 大,992px以及以上
xl: extra large, 特别大,1200px以及以上
angular5对于父元素和子元素的双向绑定定义了语法糖:
<app-sizer [(size)]="fontSizePx"></app-sizer>
等价于:
<app-sizer [size]="fontSizePx" (sizeChange)="fontSizePx=$event"></app-sizer>
模板引用变量(template reference variable)的作用于(scope)是整个的template;而模板输入变量是component的属性。模板引用变量前面的#可以用ref-代替,如下:
<input ref-fax placeholder="fax number">
<button (click)="callFax(fax.value)">Fax</button>
所有的components都是directives。
父component和子component之间可以通过服务进行通讯,服务类可以使用rxjs库的Observable和Subject类。
其中每一个Subject都是一个Observable(可观察对象),可以订阅,同时,每一个Subject也可以作为Observer(观察者),Subject同样也是一个由next(v),error(e)和complete()这些方法组成的对象。调用next(theValue)方法后,Subject会向所有已经在其上注册的Observer多路推送theValue。
angular2文档的Component Interaction最后一节的例子讲了一个向宇航员宣布任务,宇航员确认的例子:
父有个按钮“宣布”任务,
下面有三个宇航员,每个宇航员
父的构造函数订阅了服务的missionConfirmed$这个Observable
每个宇航员的component构造函数订阅了服务的missionAnnounced$这个Observable
服务有两个方法:
announceMission
confirmMission
这两个方法对Subject进行操作
点击“宣布”按钮,调用服务的announcedMission方法,把第一个任务“飞向月球”推送到每个宇航员。
router在每个模板内部只能支持一个主要的匿名outlet。
ActivatedRoute接口定义如下:
ActivatedRoute可以用来查询路由参数如/hero/:id, hero/11, 这个11能被查询到,这样就不用input参数
往component里面赋值了,全部由router来搞定。
路由特定的参数(route-specific parameters),又叫做矩阵参数(matrix parameters):
/inbox;a=v1/33;b1=v1;b2=v2
{path:'inbox', params: {a: 'v1'}}
{path:'33', params: {b1:'v1',b2:'v2'}}
导航分为命令式和声明式(imperatively navigation and declar)
默认情况下,在导航过程中路由器会重置查询参数(query params),如果想在导航过程中保持
查询参数不变,请参照下例:
router.navigate('/inbox/33/message/44',
{preserveQueryParams: true, preserveFragment: true})
RouterModule.forRoot 新建一个模块,这个模块包含所有的路由器指令,所有给定的路由,以及路由器服务本身;RouterModule.forChild 新建一个模块,这个模块包含所有的路由器指令,所有给定的路由,但是不包含路由器服务。
form,每个input元素有一个name元素,这是angular用来把这个form control注册到form里面去的。
imports, declarations, exports区别:
1. imports: 把别的module包含进来,这样本身module的component模板就能使用别的module里面的comonents,directives和pipe了;这些别的components,derectives和pipe还必须在别的module里面exports才行。
A模块imports B模块,那么B模块里面的components,directives和pipes都能被A模块里面的代码使用了,比如B模块里面有吧b1和b2两个components,那么b1和b2必须exports出来才能被A使用。
2. 微语法(microsyntax), 模板输入变量(template input variable), 结构性指令(structural directives)
结构性指令后面双引号括起来的部分叫做microsyntax.
3. 属性指令(attribute directive), 同一个html元素可以应用多个属性指令,但是结构性指令一个html元素只有一个。
4. *ngIf,不是隐藏,而是从DOM中去掉html元素。
5. 结构性指令前面的星号(*)是语法糖,会扩展为<ng-template>
6. *ngFor复杂的例子:
<div *ngFor="let hero of heroes; let i=index; let odd=odd; trackBy: trackById" [class.odd]="odd">
({{i}}) {{hero.name}}
</div>
7. 上例中hero, i, odd都是模板输入变量, 该变量用let来申明。
8. 模板引用变量(template reference variable)
9. ngIf和ngFor不能应用于同一个html元素上。
10. <ng-container>,如果使用结构性指令,但找不到宿主元素,可采用<ng-container>
11. *ngIf后面的字符串为模板表达式
12. interpolation{{}}绑定属性,angular会自动从component中抽取值显示,在任何异步事件发生之后(键盘,定时器,http响应)自动刷新显示。
{{}}之间可以写那些东西?只要是模板表达式就行,那么模板表达式能写什么东西呢?很多,例如:
a. 数学表达式, 1+1, 2*3, 但是=,+=,-=, new, ;,位运算符都不行
b. 组件自身的属性
c. 模板上下文(不是表达式上下文)之一的模板输入变量<div *ngFor="let hero of heroes">{{hero.name}}</div>
d. 模板上下文(不是表达式上下文)之一的模板引用变量<input #heroInput>{{heroInput.value}}
e. 布尔求反!是可以的
f. 组件自身的方法调用
13. 事件绑定
类似(Click)="template statements", 模板语句基本和模板表达式一样,但是人家支持=和链表达式(;和,)。
13. 模板绑定和properties以及events相关,和attributes无关,html的attribute是用来初始化DOM的properties的,初始化完了,就和它没有关系了。
14. 绑定的target是DOM里面的东西,target可以是(DOM 元素| component| directive)属性,(DOM 元素| component| directive)事件,偶然情况下也绑定到一个attribute名称。
15. 模板表达式和模板语句一样,只能引用上下文中的方法和变量,而不能引用全局的变量和方法如window等。
16. 父子component之间的交流可通过property binding:
<app-hero-detail [hero]="currentHero"></app-hero-detail>
上述这种情况其实可以通过路由器来解决。
17. property 绑定是单向的,而且是set的,无法读取目标元素的值,如果要读取,使用ViewChild和ContentChild。也不能在目标元素上调用方法。
18. 属性绑定也可以加前缀bind-代替中括号:
<img bind-src="heroImageUrl">
19. 目标名称一般来说是元素property,但是Angular会先看是不是directive的property。属性绑定后面的双引号里面的是模板表达式:template expression.
20. property binding的中括号会要求angular评估表达式的值,如果不带中括号,双引号里面内容会当做字符串。
21. attribute binding,有时目标元素只有attribute,没有property,只能用attribute binding,语法是[attr.xxx]="yyy"
22. 父组建加载子组件,通过OnChanges接口监控任何输入属性的变化(input properties)。
23. 动态组件,在一个html中写一个组件模板,但是模板的类型不是固定的,就要用到动态组件,类似多态。
24. 如果父亲组件想调用子组件的方法,可通过模板引用变量:
<button (click)="timer.start()">Start</button>
<button (click)="timer.stop()">Stop</button>
<div class="seconds">{{timer.seconds}}</div>
<app-countdown-timer #timer></app-countdown-timer>
25. 限制provider作用范围的二种方法,一是lazy load,一是组件级别的providers数组。
26. 如果一个module里面的某个组件的template需要在另外一个module里面使用,需要在该module的exprots数组里面exports该组件。
27. provider告诉injector如何创建service,没有provider,injector不知道自己要负责注入该service,也不能够创建service。
28. 两个component的template互相嵌套,里面的驻留在<ng-content>槽子里面,如下所示:
<app-hero-bio [heroId="1"><app-hero-contact></app-hero-contact></app-hero-bio>
其中外层的template如下所示:
template: `
<h4>{{hero.name}}</h4>
<ng-content></ng-content>
<textarea cols="25" [(ngModel)]="hero.description"></textarea>`,
29. @Optional修饰,告诉angular,如果找不到依赖项,请继续,不会抛出异常
30. @Host修饰,停止向host组件以外的组件去向上朝赵依赖。具体参看DI in Action
31. 想访问directive修饰的DOM元素,用ElementRef,这是DOM元素的包装器。
31. provider就是发布服务的菜谱, A provider is a recipe for delivering a service associated with a token.
32. 如果依赖是primitive类型的,而且必须是inject进来的,而不是构造函数传递进来的,就要用@Inject修饰一下,如下:
@Component({
selector: 'app-hero-of-the-month',
templateUrl: './hero-of-the-month.component.html',
providers: [
{ provide: Hero, useValue: someHero },
{ provide: TITLE, useValue: 'Hero of the Month' },
{ provide: HeroService, useClass: HeroService },
{ provide: LoggerService, useClass: DateLoggerService },
{ provide: MinimalLogger, useExisting: LoggerService },
{ provide: RUNNERS_UP, useFactory: runnersUpFactory(2), deps: [Hero, HeroService] }
]
})
export class HeroOfTheMonthComponent {
logs: string[] = [];
constructor(
logger: MinimalLogger,
public heroOfTheMonth: Hero,
@Inject(RUNNERS_UP) public runnersUp: string,
@Inject(TITLE) public title: string)
{
this.logs = logger.logs;
logger.logInfo('starting up');
}
}
33. 类-接口, class-interface,只用在依赖注入,抽象类MinimalLogger,如下:
{ provide: MinimalLogger, useExisting: LoggerService },
类接口主要用于缩小一个庞大的api到几个方法。
34. 注入令牌,InjectionToken,是指不是类对象的依赖对象,可以是简单的,如:日期,数字,字符串,或者函数,数组。
35. 获取一个组件的引用是比较棘手的。虽然应用是一颗组件树,但是并没有api可以访问这棵树。访问child引用还是有api的,但是对于parent引用,需要用到injector,因为每个组件实例都要加到injector的container中去,用DI访问父组件。
35. 如果在有组件继承的情况下要访问父组件引用,需要用类-接口,并且父组件要定义一个别名provider,参见DI in Action
36. unidirectional data flow意思是数据绑定是从父到子的,事件是从子到父的。参看:
https://stackoverflow.com/questions/39708018/angular2-unidirectional-data-flow
37. 在组件级别注册一个provider,每一个新的组件实例都会获得一个新的服务实例,而在root module级别,在所有的组件得到的服务实例是同一个。
38. 用router在不同的Component之间导航,selector就没有存在的必要了。
keyword: access, share
多态的一个例子参见DI in Action
C# HttpWebRequest发送post request到spring boot:
var httpWebRequest = (HttpWebRequest)WebRequest.Create("http://url");
httpWebRequest.ContentType = "application/json";
httpWebRequest.Method = "POST";
using (var streamWriter = new StreamWriter(httpWebRequest.GetRequestStream()))
{
string json = "{\"username\":\"james\"," +
"\"password\":\"james\"}";
streamWriter.Write(json);
streamWriter.Flush();
streamWriter.Close();
}
var httpResponse = (HttpWebResponse)httpWebRequest.GetResponse();
Content-Type实体头application/json和application/x-www-form-urlencoded区别:
第一种情况告诉web server,发送的数据格式为:
{ Name: 'John Smith', Age: 43 }
第二种告诉web server,发送的数据直接放在url中,格式为:
Name=John+Smith&Age=43
如果请求使用了application/x-www-form-urlencoded,在spring boot的controller端对传上来的参数不能使用@RequestBody
来修饰,否则会出现错误。
"Content type 'application/x-www-form-urlencoded;charset=UTF-8' not supported"
或者在Map参数前面加上@RequestParam修饰:
@PostMapping( "some/request/path" )
public void someControllerMethod( @RequestParam Map<String, String> body ) {
//work with Map
}
请求放的http报头结构:通用报头|请求报头|实体报头
响应方的http报头结构:通用报头|响应报头|实体报头
Accept代表发送端(客户端)希望接受的数据类型。
比如:application/json;charset=utf-8,代表客户端希望接受的数据类型是json类型。
用fiddler来监控.net程序发出的http请求包以及响应包:
fiddler启动之后作为默认的代理127.0.0.1:8888, 所有的本地包都会走这个代理,但是.net程序有个例外,就是看到发送到本机的http请求,就会绕过代理,所以请把host改为"ipv4.fiddler",fiddler看到这个host,会自动把host改为127.0.0.1
另外在c#代码里面,添加:
GlobalProxySelection.Select = new WebProxy("127.0.0.1", 8888);
这样,如果web server和fiddler运行在同一台机器上,所有的http请求都可以看到了,开森!!
注意:fiddler在这种情况下不能设置filter。
在Typescript里面使用第三方javascript库:
方法一:
1. 先安装js库, npm install --save underscore
2. http://microsoft.github.io/TypeSearch搜索类型文件,这里输入underscore,得到@types/underscore
3. 安装类型文件 npm install --save @types/underscore
4. import到angular4项目里面, import * as _ from 'underscore';
5. 使用:
...
import * as _ from 'underscore';
...
export class AppComponent {
constructor() {
const myArray: number[] = [9, 1, 5];
const lastItem: number = _.last(myArray); //Using underscore
console.log(lastItem); //5
}
}
方法二:
如果没有d.ts类型文件,
1. 在angular项目的typings.d.ts文件底部加上 declare module 'underscore';
2. 和方法一的4,5步一样。
方法三:
如果不想自己创建.d.ts文件,也不想申明模块,
1. 可以从网上下载js文件,放到src/assets目录下,这个目录会编译到build/assets目录里面,然后在index.html文件中:<script src="assets/jssha.js"></script>
2. 然后在要用jsSHA的地方先申明一下:
declare var jsSHA: any;
下面就可以用了。
方法四:
有的js库自身已经包含index.d.ts文件或者类似文件,这是只要npm install --save xlsx;
然后在需要用的ts文件中:
即可。
Function的bind()方法,这个方法会创建一个函数的实例,其this值会被绑定到传给bind函数的值。不像apply和call,这两个函数每次调用都需要传递作用阈对象进去(this指针)。
window.color = "red";
var o = { color: "blue" };
function sayColor(){
alert(this.color);
}
var objectSayColor = sayColor.bind(o);
objectSayColor(); //blue
类型定义文件(*.d.ts)
很多主流的库都是javascript写的,但是javascript不支持类型,为了让javascript库支持类型,以便在typescript环境中使用,需要类型定义文件(*.d.ts)。
比如在一个javascript文件中定义了一个变量和一个函数:
var temp = "hello!";
function foo(name) {
return name.substr(0, 3);
}
需要先定义一个类似于c++头文件的类型定义文件.d.ts
// file: sample01.d.ts
declare let temp: string;
declare let test: (name: string) => string;
在TypeScript文件中通过三斜线指令引用该文件
// file: sample02.ts
/// <reference path="./sample01.d.ts">
console.log(temp);
console.log(foo("world"));
switchMap类似于 mergeMap,但是当源 Observable 发出值时会取消内部 Observable 先前的所有订阅
angular2中的不同对象之间的交流:
1. 父组件访问子组件,完全通过template,在class里面没有交流:
这个方法叫做局部变量,通过local variable引用子组件:
<h3>Countdown to Liftoff (via local variable)</h3>
<button (click)="timer.start()">Start</button>
<button (click)="timer.stop()">Stop</button>
<div class="seconds">{{timer.seconds}}</div>
<app-countdown-timer #timer></app-countdown-timer>
2. 父组件访问子组件,完全通过ts代码,在类里面引用,不通过template:
这个方法需要@ViewChild和AfterViewInit接口的支持:
timer就是局部变量inject子组件,赋给一个成员变量,要用@ViewChild修饰:
@ViewChild(CountdownTimerComponent)
private timerComponent: CountdownTimerComponent;
3. 子组件通过按钮事件和父组件通信
子组件的template上有个按钮,点击按钮,告诉EventEmitter发出一个事件。父组件绑定到子组件的事件:
子组件template:
template: `
<div>
<img src="{{heroImageUrl}}">
<span [style.text-decoration]="lineThrough">
{{prefix}} {{hero?.name}}
</span>
<button (click)="delete()">Delete</button>
</div>`
子组件代码:
// This component makes a request but it can't actually delete a hero.
deleteRequest = new EventEmitter<Hero>();
delete() {
this.deleteRequest.emit(this.hero);
}
父组件的template:
<app-hero-detail (deleteRequest)="deleteHero($event)" [hero]="currentHero"></app-hero-detail>
要点:deleteRequest是子组件的属性,deleteHero是父组件的函数
有时候打开git gui会有很多明明是一样的文件,确被报告为不一样的,有很多警告,可以关掉:
git config core.autocrlf true