组件中使用_【Blazor】在ASP.NET Core中使用Blazor组件 创建一个音乐播放器

前言

Blazor正式版的发布已经有一段时间了,.NET社区的各路高手也创建了一个又一个的Blazor组件库,其中就包括了我和其他小伙伴一起参与的AntDesign组件库,于上周终于发布了第一个版本0.1.0,共计完成了59个常用组件,那么今天就来聊一聊如何在ASP.NET Core MVC项目中使用这些Blazor组件吧

环境搭建

.NET Core SDK 3.0.301

Vistual Studio 2019.16.6.3

调用Blazor组件

创建ASP.NET Core 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

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值