Angularで下にスクロールすると消えて、上にスクロールすると現れるヘッダー

FacebookのSPアプリとかのあれをAngularで実現します。 
jQuery、Angular1.x系では[Headroom.js](http://wicky.nillia.ms/headroom.js/)というライブラリで実現できるらしのですが、 
残念ながらAngular2/4系には対応していなかったので、別の方法で実装することにしました。  

実現したいのはこの動き↓ 
[Headroom.js Demo](http://wicky.nillia.ms/headroom.js/playroom/) 

## 参考

jQueryで実装している方がいたので、これを参考にしました。大変参考になりました。 
http://weboook.blog22.fc2.com/blog-entry-412.html  

Windowイベントを取得するために `HostListener` を使いました。
http://blog.yuhiisk.com/archive/2016/05/12/angular2-window-event.html  

DOMアクセスには `DOCUMENT` を使いました。
https://angular.io/api/platform-browser/DOCUMENT  

## やったこと

まずは、ベースとなるAngularプロジェクトを作成します。 
今回はangular-cliでベースのプロジェクトを作成しました。  

```
ng new angular-hide-header-sample
```

ベースにしたプロジェクト

```
src
├── src/app
│   ├── src/app/app.component.css
│   ├── src/app/app.component.html
│   ├── src/app/app.component.spec.ts
│   ├── src/app/app.component.ts
│   └── src/app/app.module.ts
├── src/assets
├── src/environments
│   ├── src/environments/environment.prod.ts
│   └── src/environments/environment.ts
├── src/favicon.ico
├── src/index.html
├── src/main.ts
├── src/polyfills.ts
├── src/styles.css
├── src/test.ts
├── src/tsconfig.app.json
├── src/tsconfig.spec.json
└── src/typings.d.ts
```

### ヘッダーコンポーネント作成

angular-cliで作成したプロジェクトにヘッダーコンポーネントを追加します。  

```
ng g component header
```

```html:header.component.html
<nav class="header">
  <!-- 実際にはここにmenuを実装 -->
  <p>header</p>
</nav>
```

```css:header.component.css
.header {
  position: fixed;
  z-index: 99;
  top: 0;
  left: 0;
  width: 100%;
  height: 60px;
  background: rgba(0,0,0,.5);
  transition: .5s;
}
```

### ヘッダーコンポーネントをapp.componentに追加

angular-cliで作成した際に作成されるtopページにそのまま追記しました。  

```html:app.component.html
<app-header></app-header>
<!--The content below is only a placeholder and can be replaced.-->
<!-- ...略 -->
```

この時点で、`npm start`を実行しブラウザから`localhost:4200`を確認すると、次のように表示されているはずです。 この時点では、hederは最上部に固定されたままですが、このあと更に修正していきます。 

![スクリーンショット 2017-08-18 22.34.02.png](https://qiita-image-store.s3.amazonaws.com/0/79414/67d16844-0d7e-fa52-5dfa-5e0009e75eed.png)

### ヘッダーコンポーネントを修正

実際に表示を切り替えるロジックを実装していきます。  
ヘッダーの位置を動的に変更するために、`[style.top.px]`でコンポーネントからcssの値を設定できるようにします。  

```html:header.component.html
<nav class="header" [style.top.px]="headerPos">
  <p>header</p>
  <!-- 実際にはここにmenuを実装 -->
</nav>
```

`Inject` `HostListener` `DOCUMENT`をそれぞれインポート 
クラスのメンバー変数のうち、`ofset`にはヘッダーの高さを指定します。  

```ts:header.component.ts
import { Component, OnInit, Inject, HostListener } from '@angular/core';
import { DOCUMENT } from '@angular/platform-browser';

@Component({
  selector: 'app-header',
  templateUrl: './header.component.html',
  styleUrls: ['./header.component.css']
})
export class HeaderComponent implements OnInit {
  private ofset: number = 60;
  private startPos: number = 0;
  private headerPos: number = 0;


  constructor(@Inject(DOCUMENT) private document: Document) { }
  ngOnInit() {
  }

  @HostListener('window:scroll', ['$event'])
  onScroll(event) {
    let currentPos = this.document.body.scrollTop;
    if(currentPos > this.startPos) {
      if(this.document.body.scrollTop >= this.ofset) {
        this.headerPos = -this.ofset;
      }
    } else {
      this.headerPos = 0;
    }
    this.startPos = currentPos;
  }

}
```

### 完成

次のような感じで、それっぽく動きます。

![8月-18-2017 23-05-42.gif](https://qiita-image-store.s3.amazonaws.com/0/79414/f7f8bef4-6d21-00fe-653a-c9ba04d9b010.gif)


## サンプル

今回作成した、サンプルプロジェクトは[GitHub](https://github.com/daikiojm/angular-hide-header-sample)に置きました。