我开始使用Blazor。我的意图是播放一个又一个随机的视频。因此,我想使用Blazor事件侦听器。但是"一体事件"并没有启动(onclick一切都很好(。
视频元素:
<figure id="video-player">
<video autoplay="autoplay" @onended="NewVideo">
@videoUrl
</video>
</figure>
代码块:
private MarkupString videoUrl;
protected override void OnInitialized()
{
NewVideo();
}
private void NewVideo()
{
videoUrl = new MarkupString($"<source src="videos/{tv.GetRandomVideoFileName()}" type="video/mp4">");
}
OnInitialized按预期工作,如果我将onended更改为onclick,则一切也正常。
值得一提的是:我知道,仅仅改变来源不会启动下一个视频。这将是我的下一个任务:(。首先,我只想更改DOM中的源代码。
简而言之,这是不受支持的,并且没有发布v5。请参阅此处的问题:
https://github.com/dotnet/aspnetcore/issues/24323
长话短说,您将不得不启动一些JS互操作。参考资料如下:https://learn.microsoft.com/en-us/aspnet/core/blazor/call-dotnet-from-javascript?view=aspnetcore-5.0#组件实例方法调用
在JS方面,您需要这样的东西:
var player = document.getElementById('player');
player.onended = (e) => {
DotNet.invokeMethodAsync('{assembly_name_here}', 'SongEnded');
};
程序集名称可能是项目的名称,如MyBlazorApp
。然后在你的组件中,你需要一个静态动作来连接:
protected override void OnInitialized()
{
action = UpdateMessage;
}
private static Action action;
private void UpdateMessage()
{
// DO STUFF HERE
}
[JSInvokable]
public static void SongEnded()
{
action.Invoke();
}
当然,这有点笨拙,但本质上是将JS事件映射到组件上的静态方法。你可能在想,";如果我有多个组件实例呢"在这种情况下,在将上下文传递给静态方法并找到正确的实例方面,您必须有一点创造性。再次,查看上面的参考资料,它有很多例子。
提出了一个避免静态方法的解决方案。在代码部分,我们需要保存DotNetObjectReference
的引用以及它的一些索引(将在JS中发挥作用(,这是示例类:
public abstract class VideoPlayerBase : ComponentBase, IDisposable
{
[Parameter] public string Source { get; set; }
[Parameter] public EventCallback VideoEndedCallback { get; set; }
[Inject] protected IJSRuntime JS { get; set; }
/// <summary>
/// DotNetObjectReference of current component instance.
/// This is used for catching `onended` event on video tag (which apparently is not supported by Blazor)
/// </summary>
private DotNetObjectReference<VideoPlayerBase>? _dotNetObjectReference;
/// <summary>
/// Index of DotNetObjectReference inside BlazorApp.dotNetObjectReferences array.
/// This is used to be able to relevant DotNetObjectReference from PriskApp.dotNetObjectReferences array.
/// </summary>
protected int DotNetObjectReferenceIndex { get; set; } = -1;
protected override async Task OnInitializedAsync()
{
await base.OnInitializedAsync();
_dotNetObjectReference = DotNetObjectReference.Create(this);
DotNetObjectReferenceIndex = await JS.InvokeAsync<int>("BlazorApp.addDotNetObjectReference", _dotNetObjectReference);
}
[JSInvokable("VideoEnded")]
public async Task VideoEndedAsync()
{
await VideoEndedCallback.InvokeAsync(null);
}
public void Dispose()
{
_dotNetObjectReference?.Dispose();
}
}
然后我们需要js部分:
var BlazorApp = BlazorApp || {
dotNetObjectReferences: [],
addDotNetObjectReference: function (dotNetObjectReference) {
PriskApp.dotNetObjectReferences.push(dotNetObjectReference);
return PriskApp.dotNetObjectReferences.length - 1;
},
getDotNetObjectReference: function (index) {
return PriskApp.dotNetObjectReferences[index];
},
};
最后是组件视图:
@inherits VideoPlayerBase
<div>
<video style="width:100%;" controls onended="(BlazorApp.getDotNetObjectReference(@DotNetObjectReferenceIndex).invokeMethodAsync('VideoEnded'))()">
<source src="@Source" type="video/mp4" controls>
Your browser does not support HTML video.
</video>
</div>
因此,基本上,这项工作是通过在OnInitializedAsync
方法中创建DotNetObjectReference
,然后调用js函数BlazorApp.addDotNetObjectReference
将该引用添加到某个js数组并获取其索引来完成的,该索引用于视图部分。然后,一旦视频结束,触发一个事件,并在其中获取相关的DotNetObjectReference
并调用其方法。