如何用Angular 2创建简单的手风琴?

时间:2017-02-08 12:42:10

标签: angular accordion

之前,我使用这个简单的脚本来创建一个简单的手风琴

(function() { 

    $('dl.accordion').on('click', 'dt', function() {
        this_= $(this);
        this_
            .addClass("selected")
            .next()
                .slideDown(200)
                .siblings('dd')
                    .slideUp(200);
        this_.siblings()
            .removeClass("selected")

    });
})();

这个HTML

<dl class="accordion">
    <dt>What are your hours?</dt>
    <dd>We are open 24/7.</dd>
    <dt>What are your hours?</dt>
    <dd>We are open 24/7.</dd>
</dl>

现在我想创建一个用Angular 2编写的代码的副本。

如何在Angular 2中创建如上所示的简单旋风?

我想我必须学习渲染器,elementRef等。 您能否建议我应该学习其他主题来创建这个主题?

3 个答案:

答案 0 :(得分:3)

试试这个解决方案,这是一个非常简单的手风琴:

应用/ accordion.component.ts

import { Component, Input, Output, EventEmitter } from '@angular/core';

@Component({
  selector: 'tp-accordion',
  template: `
    <h2 class="accordion-head" (click)="onClick($event)">{{ title }}</h2>
    <div class="accordion-body" [class.active]="active">
      <ng-content></ng-content>
    </div>
  `,
  styles: [
    `
    .accordion-head {
      cursor: pointer;
    }
    .accordion-body {
      display: none;
    }
    .accordion-body.active {
      display: block;
      -webkit-animation: fadeIn .3s;
      animation: fadeIn .3s;
    }
    @-webkit-keyframes fadeIn {
      from { opacity: 0; transform: scale(0); }
        to { opacity: 1; transform: scale(1); }
    }  
    @keyframes fadeIn {
      from { opacity: 0; transform: scale(0); }
        to { opacity: 1; transform: scale(1); }
    }
    `  
  ],
})
export class Accordion {

  @Input() title: string;

  @Input() active: boolean = false;

  @Output() toggleAccordion: EventEmitter<boolean> = new EventEmitter();

  constructor() {}

  onClick(event) {
    event.preventDefault();
    this.toggleAccordion.emit(this.active);
  }

}

应用/手风琴group.component.ts

import { Component, ContentChildren, QueryList, AfterContentInit, OnDestroy } from '@angular/core';

import { Accordion } from './accordion.component';

@Component({
  selector: 'tp-accordion-group',
  template: `
    <ng-content></ng-content>
  `
})
export class AccordionGroup {

  @ContentChildren(Accordion) accordions: QueryList<Accordion>;
  private subscriptions = [];

  private _accordions = [];

  constructor() {}

  ngAfterContentInit() {

    this._accordions = this.accordions;
    this.removeSubscriptions();
    this.addSubscriptions();

    this.accordions.changes.subscribe(rex => {
      this._accordions = rex;
      this.removeSubscriptions();
      this.addSubscriptions();
    });
  }

  addSubscriptions() {
    this._accordions.forEach(a => {
      let subscription = a.toggleAccordion.subscribe(e => {
        this.toogleAccordion(a);
      });
      this.subscriptions.push(subscription);
    });
  }

  removeSubscriptions() {
    this.subscriptions.forEach(sub => {
      sub.unsubscribe();
    });
  }

  toogleAccordion(accordion) {
    if (!accordion.active) {
      this.accordions.forEach(a => a.active = false);
    }
    // set active accordion
    accordion.active = !accordion.active;
  }

  ngOnDestroy() {
    this.removeSubscriptions();
  }

}

应用/ app.component.ts

import { Component, OnInit, OnDestroy } from '@angular/core';
import { PostsService } from './posts.service';


@Component({
  selector: 'app-root',
  template: `
    <tp-accordion-group>
      <tp-accordion *ngFor="let post of posts" [title]="post.title">
        {{ post.body }}
      </tp-accordion>
    </tp-accordion-group>
  `
})
export class AppComponent implements OnInit, OnDestroy {

  posts = [];
  private subscription: any;

  constructor(private postsSvc: PostsService) {}

  ngOnInit() {
    this.subscription = this.postsSvc.getPosts().subscribe(res => {
      if (res.length) {
        this.posts = res.slice(0, 10);
      }
    })
  }

  ngOnDestroy() {
    if (this.subscription) {
      this.subscription.unsubscribe();
    }
  }

}

应用/ posts.service.ts

import { Injectable } from '@angular/core';
import { Http } from '@angular/http';
import 'rxjs/add/operator/map';
import 'rxjs/add/operator/catch';

@Injectable()
export class PostsService {
  postsUrl: 'https://jsonplaceholder.typicode.com/posts';
  constructor(private http: Http) {

  }
  getPosts() {
    return this.http.get(this.postsUrl)
      .map(res => {
        let body = res.json();
        return body || [];
      })
      .catch(console.log);
  }
}

在线演示:https://plnkr.co/edit/xFBllK?p=preview

文件:

答案 1 :(得分:1)

问题

最重要的是要知道“GetElementbyClassName”或“GetElementbyID”将不起作用,除非在Angular 2中调用它。这是因为DOM将始终在Angular组件加载之前加载,因此永远不会有对象从...获得课程或身份证。

解决方案

Angular有一个“钩子”,你可以利用它,这将允许你在特定事件发生时运行代码,例如组件加载时ngAfterViewInit()

这可以通过使用指令来完成你的手风琴,但是如果你想运行上面的javascript,那么只需在ngAfterViewInit()中的export class componentName {}函数中运行它就可以了。< / p>

样品

以下是我完成上述内容的示例:

import { Component } from '@angular/core';

@Component({
  selector: 'events',
  templateUrl: "partials/events.html"
})
export class EventsComponent {
    ngAfterViewInit() {
        var acc = document.getElementsByClassName("accordion");
        var i;

for (i = 0; i < acc.length; i++) {
    acc[i].onclick = function(){
        this.classList.toggle("active");
        this.nextElementSibling.classList.toggle("show");
        }
    }
}

} // export class

答案 2 :(得分:1)

我不知道我的解决方案在角度范围内是否合法,但是我想出了一个使用服务的简单手风琴。

Click here to check out solution on stackblitz