1. 程式人生 > 其它 >元件中使用_【Blazor】在ASP.NET Core中使用Blazor元件 建立一個音樂播放器

元件中使用_【Blazor】在ASP.NET Core中使用Blazor元件 建立一個音樂播放器

技術標籤:元件中使用

前言

Blazor正式版的釋出已經有一段時間了,.NET社群的各路高手也建立了一個又一個的Blazor元件庫,其中就包括了我和其他小夥伴一起參與的AntDesign元件庫,於上週終於釋出了第一個版本0.1.0,共計完成了59個常用元件,那麼今天就來聊一聊如何在ASP.NETCore MVC專案中使用這些Blazor元件吧

環境搭建

.NET Core SDK 3.0.301

Vistual Studio 2019.16.6.3

呼叫Blazor元件

建立ASP.NETCore MVC專案,如果想要在已有的專案上使用AntDesign,需要確保Target Framework是netcoreapp3.1,然後在Nuget中搜索並安裝AntDesign 0.1.0版本。

修改Startup.cs

在ConfigureServices方法中新增

// add for balzorservices.AddServerSideBlazor();
// add for AntDesignservices.AddAntDesign();

在Configure方法中新增

app.UseEndpoints(endpoints =>
{
endpoints.MapControllerRoute(
name: "default",
pattern: "{controller=Home}/{action=Index}/{id?}");
// add for blazor
endpoints.MapBlazorHub();
});

修改./Views/Shared/_Layout.cshtml

在head區域新增


<link href="/_content/AntDesign/css/ant-design-blazor.css" rel="stylesheet">
<base href="/" />

在script區域新增


這裡我們需要利用一箇中間層,否則直接在View裡新增元件會有很多限制,不太方便

建立一個razor檔案./Components/HelloWorld.razor

@using AntDesign

<Button type="primary" OnClick="(e)=>OnClick(e)">@_contentButton>

@code{
private string _content = "Primay";
private void OnClick(Microsoft.AspNetCore.Components.Web.MouseEventArgs args)
{
_content += "*";
}
}

最後在View中新增剛剛新建的中間元件

修改./Views/Home/Index.cshtml,新增程式碼

<component type="typeof(HelloWorld)" render-mode="ServerPrerendered" />

Build & Run

這時候主頁應該會出現一個ant-design風格的button,點選後button的內容會變為Priamary*,每點選一次就多一個*,效果如下

21a54e66b9775c14367e4bfe98c87c9d.png

小結

一般來說,在MVC專案中,先將介面需要使用的元件組合在一起,然後整體包裝在一箇中間元件(HelloWolrd.razor)中,最後在呼叫的View中展示中間元件。可以理解為元件庫為我們提供了各種各樣的零件,中間層將這些零件(以及原生HTML標籤)組合成一個產品,最後在View中展示產品。

建立一個播放器元件

首先我們建立好需要用到的JavaScript指令碼

Nuget安裝Microsoft.TypeScript.MSBuild

建立檔案main.ts

interface Window {
SoBrian: any;
}

function Play(element, flag) {
var dom = document.querySelector(element);
if (flag) {
dom.play();
}
else {
dom.pause();
}
}

function GetMusicTime(element) {
var dom = document.querySelector(element);
let obj = {
currentTime: dom.currentTime,
duration: dom.duration
}
let json = JSON.stringify(obj);

return json
}

function SetMusicTime(element, time) {
var dom = document.querySelector(element);
dom.currentTime = time;
}

window.Music = {
print: Print,
play: Play,
getMusicTime: GetMusicTime,
setMusicTime: SetMusicTime
}

建立檔案tsconfig.json

{
"compileOnSave": true,
"compilerOptions": {
"noImplicitAny": false,
"noEmitOnError": true,
"removeComments": false,
"sourceMap": false,
"target": "es2015",
"outDir": "wwwroot/js"
},
"files": [ "main.ts" ],
"exclude": [
"node_modules",
"wwwroot"
]
}

建立資料夾./wwwroot/music/

放入幾首你喜歡的音樂,但要注意支援的檔案格式

can be used to play sound files in the following formats:
.mp3: Supported by all modern browsers.
.wav: Not supported by Internet Explorer.
.ogg: Not supported by Internet Explorer and Safari.

建立./Components/MusicPlayer.razor

@namespace SoBrian.MVC.Components
@inherits AntDesign.AntDomComponentBase

<audio id="audio" preload="auto" src="@_currentSrc">audio>
<div>
<AntDesign.Row Justify="center" Align="middle">
<AntDesign.Col Span="4">
<p>@System.IO.Path.GetFileNameWithoutExtension(_currentSrc)p>
AntDesign.Col>
<AntDesign.Col Span="4">
<AntDesign.Space>
<AntDesign.SpaceItem>
<AntDesign.Button Type="primary" Shape="circle" Icon="left" OnClick="OnLast" />
AntDesign.SpaceItem>
<AntDesign.SpaceItem>
<AntDesign.Button Type="primary" Shape="circle" Icon="@PlayPauseIcon" Size="large" OnClick="OnPlayPause" />
AntDesign.SpaceItem>
<AntDesign.SpaceItem>
<AntDesign.Button Type="primary" Shape="circle" Icon="right" OnClick="OnNext" />
AntDesign.SpaceItem>
AntDesign.Space>
AntDesign.Col>
<AntDesign.Col Span="9">
<AntDesign.Slider Value="@_currentTimeSlide" OnAfterChange="OnSliderChange" />
AntDesign.Col>
<AntDesign.Col Span="3">
<p>@($"{_currentTime.ToString("mm\\:ss")} / {_duration.ToString("mm\\:ss")}")p>
AntDesign.Col>
AntDesign.Row>
div>

建立./Components/MusicPlayer.razor.cs

public partial class MusicPlayer : AntDomComponentBase
{
private bool _isPlaying = false;
private bool _canPlayFlag = false;
private string _currentSrc;
private List<string> _musicList = new List<string>
{
"music/周杰倫 - 蘭亭序.mp3",
"music/周杰倫 - 告白氣球.mp3",
"music/周杰倫 - 聽媽媽的話.mp3",
"music/周杰倫 - 園遊會.mp3",
"music/周杰倫 - 夜曲.mp3",
"music/周杰倫 - 夜的第七章.mp3",
"music/周杰倫 - 擱淺.mp3"
};
private Timer _timer;
private double _currentTimeSlide = 0;
private TimeSpan _currentTime = new TimeSpan(0);
private TimeSpan _duration = new TimeSpan(0);
private string PlayPauseIcon { get => _isPlaying ? "pause" : "caret-right"; }
private Action _afterCanPlay; [Inject]
private DomEventService DomEventService { get; set; }

protected override void OnInitialized()
{
base.OnInitialized();

_currentSrc = _musicList[0];
_afterCanPlay = async () =>
{
// do not use _isPlaying, this delegate will be triggered when user clicked play button if (_canPlayFlag)
{
try
{
await JsInvokeAsync("Music.play", "#audio", true);
_canPlayFlag = false;
}
catch (Exception ex)
{
}
}
};
}

protected override Task OnFirstAfterRenderAsync()
{
// cannot listen to dom events in OnInitialized while render-mode is ServerPrerendered DomEventService.AddEventListener<JsonElement>("#audio", "timeupdate", OnTimeUpdate);
DomEventService.AddEventListener<JsonElement>("#audio", "canplay", OnCanPlay);
DomEventService.AddEventListener<JsonElement>("#audio", "play", OnPlay);
DomEventService.AddEventListener<JsonElement>("#audio", "pause", OnPause);
DomEventService.AddEventListener<JsonElement>("#audio", "ended", OnEnd);
return base.OnFirstAfterRenderAsync();
}

#region Audio EventHandlers
private async void OnPlayPause(MouseEventArgs args)
{
try
{
await JsInvokeAsync("Music.play", "#audio", !_isPlaying);
}
catch (Exception ex)
{
}
}

private async void OnCanPlay(JsonElement jsonElement)
{
try
{
string json = await JsInvokeAsync<string>("Music.getMusicTime", "#audio");
jsonElement = JsonDocument.Parse(json).RootElement;
_duration = TimeSpan.FromSeconds(jsonElement.GetProperty("duration").GetDouble());

_afterCanPlay();
}
catch (Exception)
{
}
}

private void OnPlay(JsonElement jsonElement)
{
_isPlaying = true;
}

private async void OnLast(MouseEventArgs args)
{
_canPlayFlag = true;
int index = _musicList.IndexOf(_currentSrc);
index = index == 0 ? _musicList.Count - 1 : index - 1;
_currentSrc = _musicList[index];
}

private async void OnNext(MouseEventArgs args)
{
_canPlayFlag = true;
int index = _musicList.IndexOf(_currentSrc);
index = index == _musicList.Count - 1 ? 0 : index + 1;
_currentSrc = _musicList[index];
}

private void OnPause(JsonElement jsonElement)
{
_isPlaying = false;
StateHasChanged();
}

private void OnEnd(JsonElement jsonElement)
{
_isPlaying = false;
StateHasChanged();

OnNext(new MouseEventArgs());
}

private async void OnTimeUpdate(JsonElement jsonElement)
{
// do not use the timestamp from timeupdate event, which is the total time the audio has been working // use the currentTime property from audio element string json = await JsInvokeAsync<string>("Music.getMusicTime", "#audio");
jsonElement = JsonDocument.Parse(json).RootElement;
_currentTime = TimeSpan.FromSeconds(jsonElement.GetProperty("currentTime").GetDouble());
_currentTimeSlide = _currentTime / _duration * 100;

StateHasChanged();
}

#endregion
private async void OnSliderChange(OneOf<double, (double, double)> value)
{
_currentTime = value.AsT0 * _duration / 100;
_currentTimeSlide = _currentTime / _duration * 100;
await JsInvokeAsync("Music.setMusicTime", "#audio", _currentTime.TotalSeconds);
}
}

建立./Controllers/MusicController.cs

public class MusicController : Controller
{
public IActionResult Index(string name)
{
return View();
}
}

建立./Views/Music/Index.cshtml

<component type="typeof(MusicPlayer)" render-mode="Server" />

修改./Views/Shared/_Layout.cshtml,新增以下程式碼

Music

Build & Run

點選選單欄的Music,效果如下

9454f7718455230011c9fbb113c9e746.png

總結

3645af6ccd3baa9fc115570c0c7b34a2.png

WebAssembly並不是JavaScript的替代品,Blazor當然也不是,在開發Blazor元件的過程中,大部分情況下,仍然要通過TypeScript / JavaScript來與DOM進行互動,比如在這個播放器的案例中,還是需要JavaScript來呼叫audio的play,pause等方法。但是在View層面使用播放器這個元件時,我們幾乎可以不再關心JavaScript的開發。這讓前端的開發更類似於開發WPF的XAML介面。事實上,社群裡也有這樣的專案,致力於提供一種類WPF介面開發的元件庫。

同時,也希望大家能多多關注國內小夥伴們共同參與開發的AntDesign,作為最熱門的Blazor元件庫之一,在今年的MS Build大會上也獲得了微軟官方的認可。雖然目前元件還有不少BUG和效能問題,但是在社群的努力下,相信它會越來越好,讓我們一起為.NET生態添磚加瓦!

社群元件庫:

https://github.com/ant-design-blazor/ant-design-blazor

https://github.com/ArgoZhang/BootstrapBlazor

參考:

https://catswhocode.com/html-audio-tag

https://www.w3schools.com/TAGS/tag_audio.asp