Xây dựng ứng dụng nghe nhạc hiện đại với Angular và Tailwind CSS

0 0 0

Người đăng: Vũ Tuấn

Theo Viblo Asia

Trong kỷ nguyên nhạc số, một ứng dụng nghe nhạc đẹp mắt và tiện dụng là điều không thể thiếu. Bài viết này sẽ hướng dẫn bạn tạo một ứng dụng nghe nhạc Harmonic Beats bằng Angular và Tailwind CSS, với các tính năng như điều hướng bài hát, thanh trượt tiến độ tùy chỉnh và danh sách phát được tuyển chọn, mang đến trải nghiệm vừa bắt mắt vừa tương tác cao.

Các tính năng chính của Harmonic Beats

  • Điều hướng bài hát: Tua tới hoặc tua lại giữa các bài hát.
  • Thanh trượt tiến độ tùy chỉnh: Được xây dựng bằng CSS để kiểm soát phát lại chính xác.
  • Quản lý danh sách phát: Hiển thị và chọn bài hát từ danh sách có thể cuộn.
  • Xử lý lỗi: Cảnh báo các sự cố phát lại.

Hướng dẫn từng bước để xây dựng ứng dụng Harmonic Beats

1. Thiết lập dự án Angular

Bắt đầu bằng cách thiết lập một dự án Angular. Nếu bạn chưa cài đặt Angular CLI, hãy cài đặt bằng lệnh:

npm install -g @angular/cli

Sau đó, tạo một dự án mới:

ng new music-player
cd music-player

Cài đặt Tailwind CSS:

npm install -D tailwindcss postcss autoprefixer
npx tailwindcss init

Định cấu hình tailwind.config.js để bao gồm các thành phần Angular:

module.exports = { content: [ "./src/**/*.{html,ts}", ], theme: { extend: {}, }, plugins: [],
}

Thêm các chỉ thị Tailwind vào src/styles.css:

@tailwind base;
@tailwind components;
@tailwind utilities;

2. Thiết kế giao diện người dùng với Tailwind CSS

Sử dụng Tailwind CSS để tạo giao diện người dùng hiện đại, đáp ứng. Dưới đây là cấu trúc HTML cho thành phần:

<div class="w-full h-screen flex flex-col items-center justify-center p-6 bg-gray-800 text-white"> <h1 class="text-3xl font-bold mb-8">Music Player</h1> @if (error()) { <div class="bg-red-500 p-4 mb-4 rounded w-full max-w-md"> <div class="flex items-center"> <span class="material-icons mr-2">error_outline</span> <div> <h4 class="font-bold">Error</h4> <p>{{ error() }}</p> </div> </div> </div> } <!-- Current Track --> <div class="text-center mb-4 w-full max-w-md"> <h2 class="text-2xl font-bold">{{ tracks[currentTrackIndex()].title }}</h2> <p class="text-gray-400">{{ tracks[currentTrackIndex()].artist }}</p> </div> <!-- Custom Slider --> <div class="relative mb-4 w-full max-w-md"> <input type="range" min="0" max="100" [value]="progress()" (input)="handleSeek($event)" class="w-full h-2 bg-gray-600 rounded-lg appearance-none cursor-pointer slider-thumb" /> </div> <!-- Player Controls --> <div class="flex justify-center space-x-4 mb-6 w-full max-w-md"> <button (click)="handlePrevious()" class="btn"> <i class="fas fa-step-backward"></i> </button> <button (click)="handlePlayPause()" class="btn"> @if (isPlaying()) { <i class="fas fa-pause"></i> } @else { <i class="fas fa-play"></i> } </button> <button (click)="handleNext()" class="btn"> <i class="fas fa-step-forward"></i> </button> </div> <!-- Track List --> <h3 class="text-xl font-semibold mb-2">Track List</h3> <div class="h-[200px] w-full max-w-md rounded-md border border-gray-700 p-4 overflow-y-auto custom-scrollbar" #trackListContainer> @for (track of tracks; track $index) { <div class="p-2 cursor-pointer hover:bg-gray-700 rounded-md" [ngClass]="{ 'bg-gray-700': $index === currentTrackIndex() }" (click)="handleTrackSelect($index)"> <p class="font-medium">{{ track.title }}</p> <p class="text-sm text-gray-400">{{ track.artist }}</p> </div> } @empty { <p class="text-gray-400">No tracks found</p> } </div>
</div>

3. Thêm tính tương tác

Định nghĩa logic trong music-player.component.ts:

  • Xử lý phát lại: Phát, tạm dừng và điều hướng bài hát.
  • Cập nhật tiến độ: Theo dõi và hiển thị tiến độ phát lại.
  • Xử lý lỗi: Cung cấp phản hồi cho người dùng về các sự cố âm thanh.
import { NgClass } from '@angular/common';
import { Component, OnInit, signal, computed, ViewChild, ElementRef,
} from '@angular/core'; interface Track { title: string; artist: string; url: string;
} @Component({ selector: 'app-root', imports: [NgClass], templateUrl: './app.component.html', styleUrl: './app.component.scss',
})
export class AppComponent implements OnInit { @ViewChild('trackListContainer') trackListContainer!: ElementRef; tracks: Track[] = [ { title: 'Serenity', artist: 'Piano and Strings', url: 'https://www.soundhelix.com/examples/mp3/SoundHelix-Song-1.mp3', }, { title: 'Energetic Beats', artist: 'Drum and Bass Collective', url: 'https://www.soundhelix.com/examples/mp3/SoundHelix-Song-2.mp3', }, { title: 'Smooth Jazz', artist: 'Sax and Keys', url: 'https://www.soundhelix.com/examples/mp3/SoundHelix-Song-3.mp3', }, { title: 'Classical Symphony', artist: 'Orchestra Ensemble', url: 'https://www.soundhelix.com/examples/mp3/SoundHelix-Song-4.mp3', }, { title: 'Electronic Dreams', artist: 'Synthwave Collective', url: 'https://www.soundhelix.com/examples/mp3/SoundHelix-Song-5.mp3', }, { title: 'Ambient Relaxation', artist: 'Chillout Lounge', url: 'https://www.soundhelix.com/examples/mp3/SoundHelix-Song-6.mp3', }, { title: 'Country Folk', artist: 'Acoustic Guitar Trio', url: 'https://www.soundhelix.com/examples/mp3/SoundHelix-Song-7.mp3', }, { title: 'Rocking Blues', artist: 'Electric Guitar Band', url: 'https://www.soundhelix.com/examples/mp3/SoundHelix-Song-8.mp3', }, { title: 'Hip Hop Beats', artist: 'Rap Collective', url: 'https://www.soundhelix.com/examples/mp3/SoundHelix-Song-9.mp3', }, { title: 'Reggae Vibes', artist: 'Island Rhythms', url: 'https://www.soundhelix.com/examples/mp3/SoundHelix-Song-10.mp3', } ]; currentTrackIndex = signal(0); isPlaying = signal(false); progress = signal(0); error = signal<string | null>(null); private audio: HTMLAudioElement | null = null; ngOnInit() { this.loadTrack(); } loadTrack() { this.audio?.pause(); this.audio = new Audio(this.tracks[this.currentTrackIndex()].url); this.audio.addEventListener('timeupdate', this.updateProgress.bind(this)); this.audio.addEventListener('ended', this.handleNext.bind(this)); this.audio.addEventListener('canplay', () => this.error.set(null)); this.audio.addEventListener('error', () => { this.error.set('Unable to load audio. Please check the audio source.'); this.isPlaying.set(false); }); } handlePlayPause() { if (this.audio) { if (this.isPlaying()) { this.audio.pause(); } else { this.audio.play().catch(() => { this.error.set('Playback failed. Please try again.'); }); } this.isPlaying.set(!this.isPlaying()); } } scrollToCurrentTrack() { const container = this.trackListContainer.nativeElement; const selectedTrack = container.children[this.currentTrackIndex()]; if (selectedTrack) { selectedTrack.scrollIntoView({ behavior: 'smooth', block: 'nearest' }); } } handleNext() { this.currentTrackIndex.set( (this.currentTrackIndex() + 1) % this.tracks.length ); this.loadTrack(); this.isPlaying.set(true); this.audio?.play(); this.scrollToCurrentTrack(); } handlePrevious() { this.currentTrackIndex.set( (this.currentTrackIndex() - 1 + this.tracks.length) % this.tracks.length ); this.loadTrack(); this.isPlaying.set(true); this.audio?.play(); this.scrollToCurrentTrack(); } handleTrackSelect(index: number) { this.currentTrackIndex.set(index); this.loadTrack(); this.isPlaying.set(true); this.audio?.play(); this.scrollToCurrentTrack(); } handleSeek(event: Event) { const input = event.target as HTMLInputElement; const value = parseFloat(input.value); this.progress.set(value); if (this.audio) { const newTime = (value / 100) * this.audio.duration; this.audio.currentTime = newTime; } } updateProgress() { if (this.audio) { const duration = this.audio.duration || 1; const currentTime = this.audio.currentTime; this.progress.set((currentTime / duration) * 100); } }
}

5. Triển khai và kiểm tra

Sử dụng Angular CLI để chạy ứng dụng cục bộ:

ng serve

Truy cập http://localhost:4200 để xem Harmonic Beats hoạt động!

Kết luận

Trong hướng dẫn này, bạn đã học cách xây dựng một ứng dụng nghe nhạc hiện đại bằng Angular và Tailwind CSS. Bằng cách kết hợp kiến trúc dựa trên thành phần của Angular với framework CSS Tailwind, bạn đã tạo ra một trình phát nhạc hấp dẫn về mặt hình ảnh và tương tác. Bạn có thể tùy chỉnh ứng dụng thêm bằng cách bổ sung các tính năng như điều khiển âm lượng, chế độ phát ngẫu nhiên hoặc chủ đề chế độ tối.

Cảm ơn các bạn đã theo dõi!

Bình luận

Bài viết tương tự

- vừa được xem lúc

The Twelve-Factor App, cẩm nang gối đầu giường trong xây dựng application (Phần 1)

Giới thiệu. Ngày nay các phần mềm được triển khai dưới dạng các dịch vụ, chúng được gọi là các web apps hay software-as-a-service (SaaS).

0 0 30

- vừa được xem lúc

8 Sai lầm phổ biến khi lập trình Android

1. Hard code.

0 0 185

- vừa được xem lúc

Popular interview question: What is the difference between Process and Thread? 10 seconds a day

Video được đăng tại channel Tips Javascript

0 0 29

- vừa được xem lúc

Thuật toán và ứng dụng - P1

Mục đích series. . Những bài toán gắn liền với thực tế. Từ đó thấy được tầm quan trọng của thuật toán trong lập trình.

0 0 35

- vừa được xem lúc

Tác dụng của Docker trong quá trình học tập

Docker bây giờ gần như là kiến thức bắt buộc đối với các anh em Dev và Devops, nhưng mà đối với sinh viên IT nói chung vẫn còn khá mơ hồ và không biết tác dụng thực tế của nó. Hôm nay mình sẽ chia sẻ

0 0 31

- vừa được xem lúc

Làm giàu trong ngành IT

Hầu như mọi người đều đi làm để kiếm tiền, ít người đi làm vì thấy cái nghề đó thú vị lắm. Bây giờ vất cho mình 100 tỷ bảo mình bỏ nghề thì mình cũng bỏ thôi.

0 0 33