使用Angular&Electron II构建音乐播放器:制作UI

In the previous post on building a music player with Angular and Electron, we were able to successfully setup an environment where our app can live. Angular was bootstrapped, Electron was loaded, and the app opens up displaying a test content.

以前的岗位上建立一个音乐播放器,角和电子,我们能够成功地设置,其中我们的应用程序能够生活的环境。 引导了Angular,加载了Electron,该应用程序打开并显示测试内容。

We also discussed the different types of components which are presentation and container components. In this part of the series, we will build our presentation components which include the following:

我们还讨论了表示和容器组件的不同类型的组件。 在本系列的这一部分中,我们将构建演示组件,其中包括:

  1. Search

    搜索
  2. Details

    细节
  3. Player

    播放器
  4. Progress

    进展
  5. Footer

    页脚

应用程式结构 ( App Structure )

Based on the Angular Style Guide, we will structure our app in a manner that every presentation component is going to be in a folder. This folder will also contain the component's HTML and CSS files. Starting from the app directory, our app structure should look like the following:

基于Angular Style Guide ,我们将以一种方式构造我们的应用程序,使每个演示组件都位于一个文件夹中。 此文件夹还将包含组件HTML和CSS文件。 从app目录开始,我们的应用程序结构应如下所示:

|--app
|----music
|------music-details
|--------music-details.component.css
|--------music-details.component.html
|--------music-details.component.ts
|------music-footer
|--------music-footer.component.css
|--------music-footer.component.html
|--------music-footer.component.ts
|------music-progress
|--------music-progress.component.ts
|--------...
|------music-search
|--------music-search.component.ts
|--------...
|------shared
|--------api.service.ts
|--------music.service.ts
|------music.module.ts
|----app.component.css
|----app.component.html
|----app.component.ts

We will not touch the shared folder and the app component in this part of the post. What we will do is build the UI components and assemble them for export using the MusicModule.

在本文的这一部分中,我们不会触摸shared文件夹和app组件。 我们要做的是构建UI组件,并使用MusicModule组装它们以进行导出。

UI线框 ( UI Wireframe )

The music player's design will take the same structure as the of the React's article and the diagram below shows a rough sketch of what we are up to:

音乐播放器的设计将采用与React文章相同的结构,下图简要展示了我们的工作:

整体风格 ( Global Styles )

Some styles like app background color, resets and tweaks for the music search text box needs to go into the global style which is located in the src folder:

某些样式(例如应用程序背景色,音乐搜索文本框的重置和调整)需要进入位于src文件夹中的全局样式:

/*
./src/styles.css
*/
*, *:before, *:after {
  box-sizing: border-box;
}

body, html {
  margin: 0;
  padding: 0;
}

body{
  background: #000;
}

.ui-autocomplete, .ui-inputtext {
  width: 100%;
  margin: 0;
}

.ui-inputtext {
  border-radius: 0;
  margin: 0;
  border: none;
  border-bottom: 2px solid rgb(21,96,150);
  outline: none;
  background: rgba(255, 255, 255, 0.8);
}

We need font-awesome fonts for our player controls. You can install the font via npm:

我们的播放器控件需要使用真棒字体。 您可以通过npm安装字体:

npm install --save font-awesome

...then add the font awesome url to the angular-cli.json styles array:

...然后将真棒字体网址添加到angular-cli.json样式数组:

"styles": [
        "../node_modules/font-awesome/css/font-awesome.css",
        "styles.css"
      ],

Restart the build process by running npm start after adding the style so it can be loaded.

添加样式后,通过运行npm start重新启动构建过程,以便可以加载它。

组件 ( Components )

We listed the UI components we need to create above. Let's do that right away, one after the other.

我们在上面列出了需要创建的UI组件。 让我们一次又一次地做到这一点。

Below, is the MusicModule which imports all the members of the music section:

下面是MusicModule ,它导入music部分的所有成员:

// ./src/app/music/music.module.ts

// Third party imports
import { NgModule } from '@angular/core';
import { FormsModule } from '@angular/forms';
import { HttpModule } from "@angular/http";
import { CommonModule } from '@angular/common';
// PrimeNG autocomplete fro search
import { AutoCompleteModule } from 'primeng/primeng';

// Custom imports
import { MusicSearchComponent } from './music-search/music-search.component';
import { MusicPlayerComponent } from './music-player/music-player.component';
import { MusicDetailsComponent } from './music-details/music-details.component';
import { MusicProgressComponent } from './music-progress/music-progress.component';
import { MusicFooterComponent } from './music-footer/music-footer.component';
import { MusicService } from './shared/music.service';
import { ApiService } from './shared/api.service';

@NgModule({
    imports: [
      // Define imports
      FormsModule,
      AutoCompleteModule,
      HttpModule,
      CommonModule
    ],
    exports: [
      // Expose components
      MusicSearchComponent,
      MusicDetailsComponent,
      MusicPlayerComponent,
      MusicProgressComponent,
      MusicFooterComponent
    ],
    declarations: [
      // Declare components
      MusicSearchComponent,
      MusicDetailsComponent,
      MusicPlayerComponent,
      MusicProgressComponent,
      MusicFooterComponent
    ],
    providers: [
      // Services
      ApiService,
      MusicService
    ],
})
export class MusicModule { }

Do not panic at the errors because we are yet to create these members and we will start doing that right away.

不要惊慌于错误,因为我们尚未创建这些成员,我们将立即开始这样做。

1.搜索组件 (1. Search Component)

The search component is an autocomplete control so rather than walk the painful stress of building it, we can just make use of what PrimeNG. PrimeNG's autocomplete is a drop and use component and very easy to setup.

搜索组件是一个自动完成控件,因此我们不必利用PrimeNG带来的痛苦,而不必花很多时间来构建它。 PrimeNG的自动完成功能是一个即用即用的组件,非常易于设置。

First, we have to install primeng:

首先,我们必须安装primeng

# Install PrimeNG
npm install primeng --save

When npm is done with the installation, import primeng to the MusicModule. We already did that:

安装primeng npm ,将primeng导入MusicModule 。 我们已经做到了:

import { AutoCompleteModule } from 'primeng/primeng';
// ...

@NgModule({
    imports: [
      // ...
      AutoCompleteModule,
      ]
})

One more thing to get done with installing PrimeNG is to install its themes and global css. You can do this the same way we installed font-awesome:

安装PrimeNG需要完成的另一件事是安装其主题和全局CSS。 您可以按照安装font-awesome的相同方式执行此操作:

"styles": [
"../node_modules/primeng/resources/themes/omega/theme.css",
        "../node_modules/primeng/resources/primeng.min.css",
        "../node_modules/font-awesome/css/font-awesome.css",
        "styles.css"
      ],

Next, we add the search template with p-autocomplete which is the name AutoComplete's selector name:

接下来,我们使用p-autocomplete添加搜索模板,该模板是AutoComplete名称的选择器名称:

SEARCH COMPONENT TEMPLATE

搜索组件模板

<!-- ./src/app/music/music-search/music-search.component.html -->
<p-autoComplete
  [ngModel]="track"
  [suggestions]="tracks"
  (completeMethod)="search($event)"
  (onSelect)="select($event)"
  field="title"
>    
  <template let-track>
    <div class="ui-helper-clearfix" style="border-bottom:1px solid #D5D5D5">
      <img src="{{track.artwork_url}}" class="artwork"/>
      <div class="text truncate">{{track.title}}</div>
    </div>
  </template>
</p-autoComplete>=

The autocomplete uses [ngModel] property to keep track of the value of the text box. [suggestions] is the list it should search in which is tracks. completeMethod is the event raised on keystrokes while onSelect is the event raised when the autocomplete suggestions item is clicked.

autocomplete使用[ngModel]属性来跟踪文本框的值。 [suggestions]是应该在搜索是列表trackscompleteMethod是击键引发的事件,而onSelect是单击autocomplete建议项时引发的事件。

The values of these events and properties are passed down from the container component, and we will see how that is done when we discuss the container component.

这些事件和属性的值从容器组件中传递下来,当我们讨论容器组件时,我们将看到如何完成这些操作。

template is used to provide a custom view for our tracks.

template用于为我们的曲目提供自定义视图。

SEARCH COMPONENT CLASS The following is the search component class:

搜索组件类以下是搜索组件类:

// ./src/app/music/music-search/music-search.component.ts
import { Component, Output, EventEmitter, Input } from '@angular/core';


@Component({
  selector: 'music-search',
  templateUrl: './music-search.component.html',
  styleUrls: ['./music-search.component.css']
})
export class MusicSearchComponent {

  track: string;
  @Input() tracks: any[];

  @Output() update = new EventEmitter();
  @Output() query = new EventEmitter();

  search(event) {
    this.query.emit(event.query);
  }

  select(track) {
    this.update.emit(track);
  }
}

See how this component completely unaware of how the tracks created or even how the search and select events are handled. All it knows is that someday, it's parent will send down tracks to it using Input decorator and when an event is raised within, it is delegated to the parent component with Output to handle.

了解该组件如何完全不知道如何创建tracks ,甚至不知道如何处理searchselect事件。 它所知道的就是,有一天,它的父级将使用Input装饰器向其发送曲目,当其中引发一个事件时,它将委托给父级组件,由Output进行处理。

We are beginning to see how UI/presentation components are dumb and unaware of a lot of things about our application.

我们开始看到UI /表示组件是如何愚蠢的,并且没有意识到有关应用程序的很多事情。

SEARCH COMPONENT STYLES

搜索组件样式

/*
./src/app/music/music-search/music-search.component.css
*/
.truncate {
  width: 400px;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.artwork{
  width:32px;
  display:inline-block;
  margin:5px 0 2px 5px;
}

.text {
  font-size:18px;
  float:right;
  margin:10px 10px 0 0;
}

2.详细信息组件 (2. Details Component)

This component is a simple one because it just has one Input propety, a title which displays the song title:

该组件很简单,因为它只有一个Input属性,即显示歌曲标题的标题:

DETAILS COMPONENT CLASS

细节等级

// ./src/app/music/music-details/music-details.component.ts
import {Component, Input} from '@angular/core';

@Component({
  selector: 'music-details',
  templateUrl: './music-details.component.html',
  styleUrls: ['./music-details.component.css'],
})
export class MusicDetailsComponent {
  @Input() title: string;
}

The component expects just one value from it's parent container for the title property.

该组件仅从其父容器获得title属性的一个值。

DETAILS COMPONENT TEMPLATE

详细信息组件模板

<!-- ./src/app/music/music-details/music-details.component.html -->
<div class="details">
  <h3>{{title}}</h3>
</div>

DETAILS COMPONENT STYLES

细节组件样式

/*
./src/app/music/music-details/music-details.component.css
*/
.details h3{
  text-align: center;
  padding: 50px 10px;
  margin: 0;
  color: white;
}

3.播放器组件 (3. Player Component)

The player component has the most controls with the most events. The controls that control sound -- play, pause, stop, forward, backward and random. The component also receives a boolean Input property to check if a song is playing or not so as to.

播放器组件具有最多的事件最多的控件。 控制声音的控件-播放,暂停,停止,前进,后退和随机播放。 该组件还接收布尔Input属性,以检查歌曲是否正在播放。

PLAYER COMPONENT CLASS

玩家组件类

// ./src/app/music/music-player/music-player.component.ts
import { Component, Output, EventEmitter, Input } from '@angular/core';

@Component({
  selector: 'music-player',
  templateUrl: './music-player.component.html',
  styleUrls: ['./music-player.component.css'],
})
export class MusicPlayerComponent {
  // If song is paused or playing    
  @Input() paused;
  // Controls
  @Output() backward = new EventEmitter();
  @Output() pauseplay = new EventEmitter();
  @Output() forward = new EventEmitter();
  @Output() random = new EventEmitter();
  @Output() stop = new EventEmitter();
}

PLAYER COMPONENT TEMPLATE

播放器组件模板

<!-- ./src/app/music/music-player/music-player.component.html -->
<div class="player">
  <div class="player__backward">
    <button (click)="backward.emit()"><i class="fa fa-backward"></i></button>
  </div>

  <div class="player__main">
    <button *ngIf="paused" (click)="pauseplay.emit()"><i class="fa fa-pause"></i></button>
    <button *ngIf="!paused" (click)="pauseplay.emit()"><i class="fa fa-play"></i></button>
    <button (click)="stop.emit()"><i class="fa fa-stop"></i></button>
    <button (click)="random.emit()"><i class="fa fa-random"></i></button>
  </div>

  <div class="player__forward">
    <button (click)="forward.emit()"><i class="fa fa-forward"></i></button>
  </div>
</div>

The snippet above shows how the events on the component class are emitted when each of the buttons is clicked. The paused property is used to toggle between the pause and the play buttons when the song is playing and paused respectively.

上面的代码片段显示了单击每个按钮时如何发出组件类上的事件。 分别在播放和暂停歌曲时, paused属性用于在暂停和播放按钮之间切换。

PLAYER COMPONENT STYLES

玩家组成风格

/*
./src/app/music/music-player/music-player.component.css
*/
.player{
  text-align: center;
  margin-top: 60px;
}

.player div{
  display: inline-block;
  margin-left: 10px;
  margin-right: 10px;
}


.player .player__backward button, .player .player__forward button{
  background: transparent;
  border: 1px solid rgb(21,96,150);
  color: rgb(24,107,160);
  width: 75px;
  height: 75px;
  border-radius: 100%;
  font-size: 35px;
  outline: none;
}

.player .player__backward button{
  border-left: none;
}

.player .player__forward button{
  border-right: none;
}

.player .player__main button:hover, .player .player__backward button:hover, .player .player__forward button:hover{
  color: rgba(24,107,160,0.7);
  border: 1px solid rgba(21,96,150,0.7);
}

.player .player__main {
  border: 1px solid rgb(21,96,150);
}

.player .player__main button {
  color: rgb(21,96,150);
  background: transparent;
  width: 75px;
  height: 75px;
  border: none;
  font-size: 35px;
  outline: none;
}

4.进展部分 (4. Progress Component)

The progress component is responsible for displaying how far into a song we have played as well as the played time and the total time it takes the play the song. This one has no events to emit but just 3 Input properties to keep track of time.

进度组件负责显示我们播放的歌曲的长度,播放的时间以及播放该歌曲所需的总时间。 这没有事件要发出,只有3个Input属性可以跟踪时间。

PROGRESS COMPONENT CLASS

进步班

// ./src/app/music/music-progress/music-progress.component.ts
import {Component, Input} from '@angular/core';

@Component({
  selector: 'music-progress',
  templateUrl: './music-progress.component.html',
  styleUrls: ['./music-progress.component.css'],
})
export class MusicProgressComponent {
  // Played
  @Input() elapsed: string;
  // Total time
  @Input() total: string;
  // Current time for the progress bar
  @Input() current: number;
}

PROGRESS COMPONENT TEMPLATE

进度组件模板

<!--./src/app/music/music-progress/music-progress.component.html-->
<div class="progress">
  <span class="player__time-elapsed">{{elapsed}}</span>
  <progress
    value="{{current}}"
    max="1"></progress>
  <span class="player__time-total">{{total}}</span>
</div>

PROGRESS COMPONENT STYLE

进度组件样式

/*
./src/app/music/music-progress/music-progress.component.css
*/
.progress{
  text-align: center;
  margin-top: 100px;
  color: white;
}

.progress progress[value] {
  /* Reset the default appearance */
  -webkit-appearance: none;
  appearance: none;

  width: 390px;
  height: 20px;
  margin-left: 4px;
  margin-right: 4px;
}

.progress progress[value]::-webkit-progress-bar {
  background-color: #eee;
  border-radius: 2px;
  box-shadow: 0 2px 5px rgba(0, 0, 0, 0.25) inset;
}

.progress progress[value]::-webkit-progress-value {
  background-color: rgb(24,107,160);
  border-radius: 2px;
  background-size: 35px 20px, 100% 100%, 100% 100%;
}

This is just for brand sake because all that matters is the HTML content that displays a tiny text and image of Scotch and Soundcloud.

这只是出于品牌考虑,因为所有重要的是HTML内容,该内容显示了Scotch和Soundcloud的微小文本和图像。

FOOTER COMPONENT CLASS

脚组件类

// ./src/app/music/music-progress/music-progress.component.ts
import { Component } from '@angular/core';

@Component({
  selector: 'music-footer',
  templateUrl: './music-footer.component.html',
  styleUrls: ['./music-footer.component.css'],
})
export class MusicFooterComponent {}

FOOTER COMPONENT TEMPLATE

脚组件模板

<!-- ./src/app/music/music-progress/music-progress.component.html -->
<div class="footer">
  <p>Love from <img src="/assets/img/logo.png" class="logo"/>
    & <img src="/assets/img/soundcloud.png" class="soundcloud"/></p>
</div>

FOOTER COMPONENT STYLES

脚部组件样式

/*
./src/app/music/music-progress/music-progress.component.css
*/
.footer{
  color: white;
  position: absolute;
  bottom: 0px;
  width: 100%;
  background: #030C12;
}

.footer p{
  text-align: center;
}

.footer .logo{
  height: 25px;
  width: auto;
}
.footer .soundcloud{
  height: 25px;
  width: auto;
}

往下 ( Up Next )

We are making great progress. We have our UI almost done and in the next (and last) post, we will tie everything together using the container component.

我们正在进步。 我们的UI 差不多完成了,在下一篇(也是最后一篇)中,我们将使用容器组件将所有内容捆绑在一起。

翻译自: https://scotch.io/tutorials/build-a-music-player-with-angular-electron-ii-making-the-ui

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值