6

Blazor 全屏按钮/全屏服务 (BootstrapBlazor组件库) - AlexChow

 2 years ago
source link: https://www.cnblogs.com/densen2014/p/16028887.html
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

Blazor 简介

Blazor 是一个使用 .NET 生成的交互式客户端 Web UI 的框架。和前端同学所熟知的 Vue、React、Angular 有巨大差异。

其最大的特色是使用 C# 代码(理论上可以是 .NET 生态的任何语言)代替 JavaScript 来实现逻辑。

  • 使用 C# 代替 JavaScript 来创建信息丰富的交互式 UI。
  • 共享使用 .NET 编写的服务器端和客户端应用逻辑。
  • 将 UI 呈现为 HTML 和 CSS,以支持众多浏览器,其中包括移动浏览器。
  • 与新式托管平台(如 Docker)集成。
  • 使用 .NET 和 Blazor 生成混合桌面和移动应用。

使用 .NET 进行客户端 Web 开发可提供以下优势:

  • 使用 C# 代替 JavaScript 来编写代码。
  • 利用现有的 .NET 库生态系统。
  • 在服务器和客户端之间共享应用逻辑。
  • 受益于 .NET 的性能、可靠性和安全性。
  • 使用开发环境(例如 Visual Studio 或 Visual Studio Code)保持 Windows、Linux 或 macOS 上的工作效率。
  • 以一组稳定、功能丰富且易用的通用语言、框架和工具为基础来进行生成。

有两种不同开发模式

Blazor WebAssembly, C# 代码运行在浏览器中。
Blazor Server,C# 代码在服务器端执行,使用 SignalR 同步到浏览器进行更新。

Blazor 涉及技术

Blazor 是 apt.net core 生态的组成部分,所涉及到的技术也大部分和 .net 相关。

视图层,使用 Razor 3 技术进行前端的编排渲染。Razor是一种标记语法,是 asp.net core 的默认视图语法,最显著的特点是强类型(C#、VB等)的代码可以和 HTML 写在一个文件中,当然也可以分开。在 razor 文件中,@符号后面的都是强类型语言,可以是一行中的一部分,也可以是一整行,还可以是一个段落。在 asp.net core 中的大致做法是把 VB、C# 等强类型语言嵌入到网页,当网页被请求的时候,在服务器端执行嵌入的代码,动态生成页面。

以 Blazor WebAssembly 开发方式运行时,依赖 WebAssembly 4 技术,可以做成静态页面不依赖任何后端服务器。

以 Blazor Server 方式开发运行时,依赖 SignalR 5 技术,并且需要后端服务器端配合。

Bootstrap 风格的 Blazor UI 组件库 - BootstrapBlazor

https://www.blazor.zone/index

基于 Bootstrap 样式库精心打造,并且额外增加了 100 多种常用的组件,为您快速开发项目带来非一般的感觉.

Element.requestFullscreen()

参考资料 https://developer.mozilla.org/zh-CN/docs/Web/API/Element/requestFullScreen

Element.requestFullscreen() 方法用于发出异步请求使元素进入全屏模式。

调用此API并不能保证元素一定能够进入全屏模式。如果元素被允许进入全屏幕模式,返回的Promise会resolve,并且该元素会收到一个fullscreenchange (en-US)事件,通知它已经进入全屏模式。如果全屏请求被拒绝,返回的promise会变成rejected并且该元素会收到一个fullscreenerror (en-US)事件。如果该元素已经从原来的文档中分离,那么该文档将会收到这些事件。

早期的Fullscreen API实现总是会把这些事件发送给document,而不是调用的元素,所以你自己可能需要处理这样的情况。参考 Browser compatibility in [Page not yet written] 来得知哪些浏览器做了这个改动。

注意:这个方法只能在用户交互或者设备方向改变的时候调用,否则将会失败。

语法

var Promise = Element.requestFullscreen(options);

参数

options 可选

一个FullscreenOptions (en-US)对象提供切换到全屏模式的控制选项。目前,唯一的选项是navigationUI (en-US),这控制了是否在元素处于全屏模式时显示导航条UI。默认值是"auto",表明这将由浏览器来决定是否显示导航条。

返回值

在完成切换全屏模式后,返回一个已经用值 undefined resolved的Promise

异常

requestFullscreen() 通过拒绝返回的 Promise来生成错误条件,而不是抛出一个传统的异常。拒绝控制器接收以下的某一个值:

TypeError

在以下几种情况下,会抛出TypeError:
文档中包含的元素未完全激活,也就是说不是当前活动的元素。
元素不在文档之内。
因为功能策略限制配置或其他访问控制,元素不被允许使用"fullscreen"功能。
元素和它的文档是同一个节点。

初步构建组件

1.建立js脚本

        bb_Fullscreen: function (ele) {
            ele.requestFullscreen() ||
                ele.webkitRequestFullscreen ||
                ele.mozRequestFullScreen ||
                ele.msRequestFullscreen;
        },
        bb_ExitFullscreen: function () {
            if (document.exitFullscreen) {
                document.exitFullscreen();
            }
            else if (document.mozCancelFullScreen) {
                document.mozCancelFullScreen();
            }
            else if (document.webkitExitFullscreen) {
                document.webkitExitFullscreen();
            }
            else if (document.msExitFullscreen) {
                document.msExitFullscreen();
            }
        }
    });

2.建立Razor页面测试

以下为简化代码,运行测试一下功能是否达到需求.

<button @onclick="FullScreen">全屏</button>
<button @onclick="ExitFullScreen">退出全屏</button>

@code{
[Inject] IJSRuntime? JSRuntime{ get; set; }

  //进入全屏
  private Task FullScreen() => await JSRuntime.InvokeVoidAsync("bb_Fullscreen");

  //退出全屏
  private Task ExitFullScreen() => await JSRuntime.InvokeVoidAsync("bb_ExitFullscreen");
}

3.优化逻辑,添加单按钮全屏切换逻辑,添加针对单独元素的全屏逻辑

JS完整代码

(function ($) {
    $.extend({
        bb_toggleFullscreen: function (el, id) {
            var ele = el;
            if (!ele || ele === '') {
                if (id) {
                    ele = document.getElementById(id);
                }
                else {
                    ele = document.documentElement;
                }
            }
            if ($.bb_IsFullscreen()) {
                $.bb_ExitFullscreen();
                ele.classList.remove('fs-open');
            }
            else {
                $.bb_Fullscreen(ele);
                ele.classList.add('fs-open');
            }
        },
        bb_Fullscreen: function (ele) {
            ele.requestFullscreen() ||
                ele.webkitRequestFullscreen ||
                ele.mozRequestFullScreen ||
                ele.msRequestFullscreen;
        },
        bb_ExitFullscreen: function () {
            if (document.exitFullscreen) {
                document.exitFullscreen();
            }
            else if (document.mozCancelFullScreen) {
                document.mozCancelFullScreen();
            }
            else if (document.webkitExitFullscreen) {
                document.webkitExitFullscreen();
            }
            else if (document.msExitFullscreen) {
                document.msExitFullscreen();
            }
        },
        bb_IsFullscreen: function () {
            return document.fullscreen ||
                document.webkitIsFullScreen ||
                document.webkitFullScreen ||
                document.mozFullScreen ||
                document.msFullScreent;
        }
    });
})(jQuery);
<button @onclick="ToggleFullScreen">全屏</button>

@code{
[Inject] IJSRuntime? JSRuntime{ get; set; }

  //全屏方法,已经全屏时再次调用后退出全屏
  private Task ToggleFullScreen() => await JSRuntime.InvokeVoidAsync("bb_toggleFullscreen");
}

4.封装为服务

再次进行思考,如果将一颗按钮封装为组件,那只有UI界面才能调用,而且式样什么的都不算最灵活,为何不做成一个服务,与UI分开解耦呢? 别着急, 马上开干.

我作为一个blazor爱好者,每一个想法,转化为一个组件后,是值得提交到例如BootstrapBlazor之类组件库大家一起学习一起进步的,自从我2020-09-25把ZXingBlazor组件提交到BootstrapBlazor之后,从自嗨到团队合作,真的学习到了很多知识和技巧,在学习BB的源码的过程中,深刻体会到了那句话的精髓:"每入一寸就有一寸的惊喜!".

项目负责人Argo作为一位微软MVP和业内人士,对整个微软技术栈有很深刻的认识和思考,对我本人更是帮助巨大,在此谢谢Argo, 😃

最后版本代码已经提交为组件库里面的一个组件,所以有些代码继承了组件库的功能,如果运行跟默认Blazor工程有不一致的地方,大家可以Fork到自己仓库去试验,以下文章不再赘述.

构建服务 FullScreenService.cs

using Microsoft.AspNetCore.Components;

namespace BootstrapBlazor.Components;

/// <summary>
/// FullScreen 服务
/// </summary>
public class FullScreenService : BootstrapServiceBase<FullScreenOption>
{
    /// <summary>
    /// 全屏方法,已经全屏时再次调用后退出全屏
    /// </summary>
    /// <param name="option"></param>
    /// <returns></returns>
    public Task Toggle(FullScreenOption? option = null) => Invoke(option ?? new());

    /// <summary>
    /// 通过 ElementReference 将指定元素进行全屏
    /// </summary>
    /// <param name="element"></param>
    /// <returns></returns>
    public Task ToggleByElement(ElementReference element) => Invoke(new() { Element = element });

    /// <summary>
    /// 通过元素 Id 将指定元素进行全屏
    /// </summary>
    /// <param name="id"></param>
    /// <returns></returns>
    public Task ToggleById(string id) => Invoke(new() { Id = id });
}

全屏服务类 FullScreenOption.cs

using Microsoft.AspNetCore.Components;

namespace BootstrapBlazor.Components;

/// <summary>
/// FullScreen 配置类
/// </summary>
public class FullScreenOption
{
    /// <summary>
    /// 
    /// </summary>
    public ElementReference Element { get; set; }

    /// <summary>
    /// 
    /// </summary>
    public string? Id { get; set; }
}
 services.TryAddScoped<FullScreenService>();

FullScreen.cs

using Microsoft.AspNetCore.Components;

namespace BootstrapBlazor.Components;

/// <summary>
/// FullScreen 组件部分类
/// </summary>
public class FullScreen : BootstrapComponentBase, IDisposable
{
    /// <summary>
    /// DialogServices 服务实例
    /// </summary>
    [Inject]
    [NotNull]
    private FullScreenService? FullScreenService { get; set; }

    /// <summary>
    /// OnInitialized 方法
    /// </summary>
    protected override void OnInitialized()
    {
        base.OnInitialized();

        // 注册 FullScreen 弹窗事件
        FullScreenService.Register(this, Show);
    }

    /// <summary>
    /// OnAfterRenderAsync 方法
    /// </summary>
    /// <param name="firstRender"></param>
    /// <returns></returns>
    protected override async Task OnAfterRenderAsync(bool firstRender)
    {
        await base.OnAfterRenderAsync(firstRender);

        if (Option != null)
        {
            await JSRuntime.InvokeVoidAsync(Option.Element.Context != null ? Option.Element : "", "bb_toggleFullscreen", Option.Id ?? "");
            Option = null;
        }
    }

    private FullScreenOption? Option { get; set; }

    private Task Show(FullScreenOption option)
    {
        Option = option;
        StateHasChanged();
        return Task.CompletedTask;
    }

    /// <summary>
    /// Dispose 方法
    /// </summary>
    /// <param name="disposing"></param>
    protected virtual void Dispose(bool disposing)
    {
        if (disposing)
        {
            FullScreenService.UnRegister(this);
        }
    }

    /// <summary>
    /// Dispose 方法
    /// </summary>
    public void Dispose()
    {
        Dispose(disposing: true);
        GC.SuppressFinalize(this);
    }
}

组件方式调用 [简化版] FullScreenButton.Razor

@namespace BootstrapBlazor.Components
@inherits TooltipComponentBase

<a @attributes="AdditionalAttributes" id="@Id" class="@ClassString" @onclick="ToggleFullScreen">
    <i class="@ButtonIconString"></i>
    <i class="@FullScreenIconString"></i>
</a>

<CascadingValue Value="this" IsFixed="true">
    <Tooltip Title="@Title" />
</CascadingValue>

@code{ 

    [Inject]
    [NotNull]
    private FullScreenService? FullScrenService { get; set; }

    private Task ToggleFullScreen() => FullScrenService.Toggle();
}

5.FullScreens 全屏示例代码

Razor

@page "/fullscreens"
@inject IStringLocalizer<FullScreens> Localizer

<h3>@Localizer["Title"]</h3>

<h4>@((MarkupString)Localizer["H1"].Value)</h4>

<DemoBlock Title="@Localizer["Block1Title"]" Introduction="@Localizer["Block1Intro"]" Name="Normal">
    <Button Text="@Localizer["ButtonText1"]" OnClick="ToggleFullScreen"></Button>
</DemoBlock>

<DemoBlock Title="@Localizer["Block2Title"]" Introduction="@Localizer["Block2Intro"]" Name="Title">
    <ul class="ul-demo mb-3">
        <li>@((MarkupString)Localizer["Li1"].Value)</li>
        <li>@((MarkupString)Localizer["Li2"].Value)</li>
    </ul>
    <FullScreenButton Title="@Localizer["Button1Text"]" FullScreenIcon="fa fa-fa" />
    <Pre class="mt-3"><@Localizer["Pre"]" /></Pre>
</DemoBlock>
using BootstrapBlazor.Components;
using Microsoft.AspNetCore.Components;

namespace BootstrapBlazor.Shared.Samples;

/// <summary>
/// FullScreens 全屏示例代码
/// </summary>
public partial class FullScreens
{
    [Inject]
    [NotNull]
    private FullScreenService? FullScreenService { get; set; }

    private async Task ToggleFullScreen()
    {
        await FullScreenService.Toggle();
    }
}

BootstrapBlazor提交组件简单步骤

  1. 添加对应组件中文资源到 BootstrapBlazor.Shared/Locales/zh.json 文件
"BootstrapBlazor.Shared.Pages.Coms": {
  ...
  "FullScreenText": "全屏组件 FullScreen",
  ...
},
"BootstrapBlazor.Shared.Samples.FullScreens": {
  "Title": "FullScreen 全屏",
  "Block1Title": "基本用法",
  ...
}
  1. 添加对应组件中文资源到 BootstrapBlazor.Shared/Locales/en.json 文件
"BootstrapBlazor.Shared.Pages.Coms": {
  ...
  "FullScreenText": "FullScreen",
  ...
},
"BootstrapBlazor.Shared.Samples.FullScreens": {
  "Title": "FullScreen",
  "Block1Title": "Basic usage",
  ...
}
  1. 添加示例到"组件" 页面

    BootstrapBlazor.Shared/Pages/Coms.razor文件,找到某个组件大类别,例如导航组件 <ComponentCategory Text="@Localizer["Text2"]">

<ComponentCategory Text="@Localizer["Text2"]">
  ...
  <ComponentCard Text="@Localizer["FullScreenText"]" Image="FullScreen.jpg" Url="fullscreens"></ComponentCard>
  ...
</ComponentCategory>
  1. BootstrapBlazor.Shared/docs.json添加
"fullscreens": "FullScreens",
  1. NavMenu.razor
    private void AddNavigation(DemoMenuItem item)
    {
        item.Items = new List<DemoMenuItem>
        {
            ...
            new()
            {
                IsNew = true,
                Text = Localizer["FullScreen"],
                Url = "fullscreens"
            },
            ...
        };

        AddBadge(item);
    }
  1. 示例文件 BootstrapBlazor.Shared/Samples/FullScreens.razor
@page "/fullscreens"
@inject IStringLocalizer<FullScreens> Localizer

<h3>@Localizer["Title"]</h3>

<DemoBlock Title="@Localizer["Block1Title"]" Introduction="@Localizer["Block1Intro"]" Name="Normal">
    <Button Text="@Localizer["ButtonText1"]" OnClick="ToggleFullScreen"></Button>
</DemoBlock>

<DemoBlock Title="@Localizer["Block2Title"]" Introduction="@Localizer["Block2Intro"]" Name="Title">
    <FullScreenButton Title="@Localizer["Button1Text"]" FullScreenIcon="fa fa-fa" />
</DemoBlock>
  1. 示例文件 BootstrapBlazor.Shared/Samples/FullScreens.razor.cs
using BootstrapBlazor.Components;
using Microsoft.AspNetCore.Components;

namespace BootstrapBlazor.Shared.Samples;

/// <summary>
/// FullScreens 全屏示例代码
/// </summary>
public partial class FullScreens
{
    [Inject]
    [NotNull]
    private FullScreenService? FullScreenService { get; set; }

    private async Task ToggleFullScreen()
    {
        await FullScreenService.Toggle();
    }
}

ASP.NET Core Blazor https://docs.microsoft.com/zh-cn/aspnet/core/blazor/?view=aspnetcore-6.0
五分钟了解 Blazor https://segmentfault.com/a/1190000040800253
Element.requestFullscreen() https://developer.mozilla.org/zh-CN/docs/Web/API/Element/requestFullScreen
Bootstrap 风格的 Blazor UI 组件库 https://www.blazor.zone/index
!1821 feat(#I48WXD): add FullScreen component https://gitee.com/LongbowEnterprise/BootstrapBlazor/commit/30caa995eba38e91d15b8a5465c6c9c738db068f

Github | Gitee

BA & Blazor QQ群:795206915、675147445

知识共享许可协议

本作品采用 知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议 进行许可。欢迎转载、使用、重新发布,但务必保留文章署名AlexChow(包含链接: https://github.com/densen2014 ),不得用于商业目的,基于本文修改后的作品务必以相同的许可发布。如有任何疑问,请与我联系

AlexChow

今日头条 | 博客园 | 知乎 | Gitee | GitHub


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK