通过Blazor使用C#开发SPA单页面应用程序(4) - Ant Design Button

前面学习了Blazor的特点、环境搭建及基础知识,现在我们尝试的做个实际的组件。

Ant Design是蚂蚁金服是基于Ant Design设计体系的 UI 组件库,主要用于研发企业级中后台产品。目前官方是基于React和Angular实现的,今年也推出了Vue的实现。其组件涵盖面较广,其组件风格及交互效果还是比较惊艳的,后面准备利用Ant Design的样式文件利用Blazor模仿几个组件的实现。

由于也是新学的Blazor开发,可能实现的方式有些笨拙,希望高手提出宝贵意见,先看看实现的Button 按钮、Grid 栅格、导航栏的效果。

先来看看Button按钮,它支持多种风格,是否只显示图标,loading状态等。实现步骤及主要代码且听我娓娓道来,

1、引用样式文件

首先去antd.css cdn 下载稳定版的css文件,放到 wwwroot 文件夹下。再 _Host.cshtml 引用该文件。

2、建立 AButtonBase 类

AButtonBase类定义了按钮的属性参数;注册了class名称(例如:class="ant-btn ant-btn-primary")的计算表达式,class内容是根据属性参数的设置情况计算出来的。

属性set 的 ClassMapper.Dirty() 是通知样式名生成方法属性改变了需要重新生成样式名称。

而ClassMapper是用于注册组件需要用到的样式构建类,PrefixCls()是添加样式共用的前缀,Add有多个重载,可以是直接的样式名称;也可以是根据第一个参数的bool表达式来确定,第二个参数的样式是否启用。

using BlazorAntDesign.Core;
using Microsoft.AspNetCore.Components;
using Microsoft.AspNetCore.Components.RenderTree;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;

namespace BlazorAntDesign.General
{    public class AButtonBase : BaseComponent
    {
        #region Properties
        /// <summary>
        /// 设置按钮大小,可选值为 Small、Large 或者不设
        /// </summary>
        [Parameter]
        protected AButtonSizes ButtonSize
        {
            get => buttonSize;
            set
            {
                buttonSize = value;
                ClassMapper.Dirty();
            }
        }
        private AButtonSizes buttonSize = AButtonSizes.Default;

        /// <summary>
        /// 设置按钮类型,可选值为 Primary、Dashed、Danger 或者不设
        /// </summary>
        [Parameter]
        protected AButtonTypes ButtonType
        {
            get => buttonType;
            set
            {
                buttonType = value;
                ClassMapper.Dirty();
            }
        }
        private AButtonTypes buttonType = AButtonTypes.Default;

        /// <summary>
        /// 设置按钮形状,可选值为 Circle、 Round 或者不设
        /// </summary>
        [Parameter]
        protected AButtonShapes ButtonShape
        {
            get => buttonShape;
            set
            {
                buttonShape = value;
                ClassMapper.Dirty();
            }
        }
        private AButtonShapes buttonShape = AButtonShapes.Default;

        /// <summary>
        /// 设置 button 原生的 type 值,可选值请参考 HTML 标准
        /// </summary>
        [Parameter]
        protected AButtonHTMLTypes HtmlType { get; set; } = AButtonHTMLTypes.Button;

        /// <summary>
        /// 按钮标题
        /// </summary>
        [Parameter]
        protected string Title
        {
            get => title;
            set
            {
                title = value;
                ClassMapper.Dirty();
            }
        }
        private string title;

        /// <summary>
        /// 设置按钮的图标名称
        /// </summary>
        [Parameter]
        protected string IconName { get; set; }

        /// <summary>
        /// 将按钮宽度调整为其父宽度的选项
        /// </summary>
        [Parameter]
        protected bool Block
        {
            get => block;
            set
            {
                block = value;
                ClassMapper.Dirty();
            }
        }
        private bool block;

        /// <summary>
        /// 幽灵属性,使按钮背景透明。幽灵按钮将按钮的内容反色,背景变为透明,常用在有色背景上。
        /// </summary>
        [Parameter]
        protected bool Ghost
        {
            get => ghost;
            set
            {
                ghost = value;
                ClassMapper.Dirty();
            }
        }
        private bool ghost;

        /// <summary>
        /// 设置按钮载入状态
        /// </summary>
        [Parameter]
        protected bool Loading
        {
            get => loading;
            set
            {
                loading = value;
                ClassMapper.Dirty();
            }
        }
        private bool loading;

        /// <summary>
        /// 按钮失效状态
        /// </summary>
        [Parameter]
        protected bool Disabled { get; set; }

        [Parameter]
        protected RenderFragment ChildContent { get; set; }

        /// <summary>
        /// 点击按钮时的回调
        /// </summary>
        [Parameter]
        public EventCallback<UIMouseEventArgs> OnClick { get; set; }
        //protected System.Action Clicked { get; set; }

        protected bool click_animating { get; set; }
        #endregion

        protected override void RegisterClasses()
        {
            ClassMapper.PrefixCls("ant-btn")
                    .Add(() => ClassMapper.GetEnumName(buttonSize))
                    .Add(() => ClassMapper.GetEnumName(buttonType))
                    .Add(() => ClassMapper.GetEnumName(buttonShape))
                    .Add(() => Block, () => "block")
                    .Add(() => Ghost, () => "background-ghost")
                    .Add(() => Loading, () => "loading")
                    .Add(() => string.IsNullOrEmpty(title) && ChildContent == null, () => "icon-only");

            base.RegisterClasses();
        }

        protected void buttonDown()
        {
            click_animating = false;
        }

        protected void buttonUp()
        {
            click_animating = true;
        }

    }
}

AButtonSizes、AButtonTypes、AButtonShapes、AButtonHTMLTypes 属性参数是定义的枚举,例如:

namespace BlazorAntDesign.General
{
    /// <summary>
    /// 按钮尺寸选项
    /// </summary>
    public enum AButtonSizes
    {
        /// <summary>
        /// 缺省,中
        /// </summary>
        [ClassNamePart("")]
        Default,

        /// <summary>
        /// 大
        /// </summary>
        [ClassNamePart("lg")]
        Large,

        /// <summary>
        /// 小
        /// </summary>
        [ClassNamePart("sm")]
        Small
    }
}
namespace BlazorAntDesign.General
{
    /// <summary>
    /// 按钮类型选项
    /// </summary>
    public enum AButtonTypes
    {
        /// <summary>
        /// 缺省,次按钮
        /// </summary>
        [ClassNamePart("")]
        Default,

        /// <summary>
        /// 主按钮
        /// </summary>
        Primary,

        /// <summary>
        ///
        /// </summary>
        Ghost,

        /// <summary>
        /// 虚线按钮
        /// </summary>
        Dashed,

        Danger
    }
}

AButtonBase类继承自自定义的BaseComponent,BaseComponent继承自Blazor的ComponentBase类。

BaseComponent主要定义了所有组件共用的属性,ElementId、Style、ClassMapper等,

using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Components;

namespace BlazorAntDesign.Core
{
    public abstract class BaseComponent : ComponentBase, IDisposable
    {
        #region Members

        private bool disposed;

        private ElementRef elementRef;

        #endregion

        #region Constructors

        public BaseComponent()
        {
            ElementId = Utils.IDGenerator.Instance.Generate;

            ClassMapper = new ClassMapper();
            RegisterClasses();
        }

        #endregion

        #region Methods
        protected virtual void RegisterClasses()
        {
            ClassMapper.AddCustomClass(() => customClass);
        }

        public void Dispose()
        {
            Dispose(true);
            GC.SuppressFinalize(this);
        }

        protected virtual void Dispose(bool disposing)
        {
            if (!disposed)
            {
                if (disposing)
                {
                    if (ClassMapper != null)
                    {
                        //ClassMapper.Dispose();
                        ClassMapper = null;
                    }
                }

                disposed = true;
            }
        }

        #endregion

        #region Properties

        /// <summary>
        /// 定义用户自定义的 ClassName
        /// </summary>
        [Parameter]
        protected string ClassName
        {
            get => customClass;
            set
            {
                customClass = value;
                ClassMapper.Dirty();
            }
        }
        private string customClass;

        /// <summary>
        /// Gets the reference to the rendered element.
        /// </summary>
        public ElementRef ElementRef { get => elementRef; protected set => elementRef = value; }

        /// <summary>
        /// 获取 element 唯一 Id.
        /// </summary>
        public string ElementId { get; }

        [Parameter]
        protected string Style { get; set; }

        /// <summary>
        /// 获取 ClassMapper.
        /// </summary>
        protected ClassMapper ClassMapper { get; private set; }

        #endregion
    }
}

3、建立 AButton.razor

@inherits BlazorAntDesign.General.AButtonBase

<button class="@ClassMapper.Class"
        type="@(Enum.GetName(typeof(AButtonHTMLTypes), HtmlType).ToLower())"
        ant-click-animating-without-extra-node="@(click_animating ? "true" : "")"
        disabled="@Disabled"
        @onkeydown="@buttonDown"
        @onmousedown="@buttonDown"
        @onkeyup="@buttonUp"
        @onmouseup="@buttonUp"
        @onclick="@OnClick">
    @*图标*@
    @if (Loading)
    {<AIcon IconName="loading"></AIcon>}
    else
    {
        if (!string.IsNullOrEmpty(IconName))
        {<AIcon IconName="@IconName"></AIcon>}
    }
    @*标题*@
    @if (!string.IsNullOrEmpty(Title))
    {<span>@Title</span>}
@*子内容*@
    @ChildContent</button>

其中  @inherits BlazorAntDesign.General.AButtonBase 是代码隐藏方式,指定后台代码继承自AButtonBase类,button class="@ClassMapper.Class",将采用的样式根据指定的属性值计算出来赋值给button的class属性。下面根据属性设置判断是否显示图标、标题、子内容。

4、使用 AButton

建立DemoButton.razor文件,样例代码如下:

@page "/DemoButton"
@using BlazorAntDesign.General;

<div style="border:1px solid beige;padding:10px">
    <AButton Title="Default"></AButton>
    <AButton Title="Primary" ButtonType="AButtonTypes.Primary"></AButton>
    <AButton Title="Danger" ButtonType="AButtonTypes.Danger"></AButton>
    <AButton Title="Dashed" ButtonType="AButtonTypes.Dashed"></AButton>
    <AButton Title="Disabled" Disabled="true"></AButton>
    <AButton ButtonType="AButtonTypes.Primary" IconName="download" ButtonShape="AButtonShapes.Circle"></AButton>
    <AButton Title="下载" ButtonType="AButtonTypes.Primary" IconName="download" ButtonShape="AButtonShapes.Round"></AButton>
    <AButton Title="下载" ButtonType="AButtonTypes.Primary" IconName="download"></AButton>
    <AButtonGroup><AButton ButtonType="AButtonTypes.Primary" IconName="left">Backward</AButton><AButton ButtonType="AButtonTypes.Primary">Forward<AIcon IconName="right" /></AButton></AButtonGroup>
    <AButton Title="Loading" ButtonType="AButtonTypes.Primary" Loading="true"></AButton>
    <AButton Title="Click me!" ButtonType="AButtonTypes.Primary" Loading="@isLoading" OnClick="@(()=> { isLoading = true; })"></AButton>
</div>
<div style="border:1px solid beige;padding:10px;margin-top:5px">
    <AButton IconName="search" ButtonType="AButtonTypes.Primary" ButtonShape="AButtonShapes.Circle"></AButton>
    <AButton IconName="search" ButtonType="AButtonTypes.Primary">按钮</AButton>
    <AButton IconName="search" ButtonShape="AButtonShapes.Circle"></AButton>
    <AButton IconName="search">按钮</AButton>
    <AButton IconName="search" ButtonType="AButtonTypes.Dashed" ButtonShape="AButtonShapes.Circle"></AButton>
    <AButton IconName="search" ButtonType="AButtonTypes.Primary">按钮</AButton>
</div>

@code{
    private bool isLoading = false;

    private void LoadingClick()
    {
        isLoading = true;
    }
}

@page "/DemoButton"   为组件路由

@using BlazorAntDesign.General;       为应用组件命名空间

好了Button的实现思路今天就学习到这了,希望有兴趣的同仁共同学习探讨,让Blazor真正走向SPA开发的舞台,让.net core七龙珠面向全栈开发,更好的拥抱社区,刷新业界对.net体系的认知。

   番   外   篇   

Blazor 在发展:

微软已将 Blazor 移出了实验阶段,进入了官方预览版。使用组件模型进行服务器端渲染的 Blazor 版本将与.NET Core 3 的最终版本一起发布(请参阅.NET Core 路线图),客户端版本将在随后不久发布。还有工作要完成:调试体验极其有限,必须改进;有机会通过提前编译生成本机 Wasm 来优化代码性能;在将未使用的代码库发送到浏览器之前,需要从库中删除未使用的代码,从而降低总体大小(这个过程称为树抖动)。对 WebAsssembly 的兴趣和采用与日俱增,借助 Blazor,编写可以在任何地方运行的 C#和.NET 代码的梦想终于实现了。

.net core将踏上新的征程:

原文地址:https://www.cnblogs.com/liuxtj/p/11377680.html

时间: 2024-11-29 08:19:20

通过Blazor使用C#开发SPA单页面应用程序(4) - Ant Design Button的相关文章

SPA 单页面应用程序。

看到这个问题,先说下自己的理解到的程度,再去参考做修正,争取这一次弄懂搞清楚 自己的理解: 单页面应用程序,解决浏览器获取数据刷新页面的尴尬,通过ajax请求获取数据达到异步更新视图的按钮,原理的实现由两种, 其一,通过hash值的变化,绑定onhashchange的回调函数更新视图,因为hash值的变化不会让页面失去响应,不会向服务器发送请求.下面列出几种可能改变hash值的方法,改变url中的hash.浏览器回退按钮可能出现历史记录中的url包含的hash值不一样,都将触发该事件:还有触发带

SPA单页面应用router实现

spa 单页面router 主要可以基于两种方式实现:修改哈希和直接修改url 1.根据在使用location 修改哈希的时候,页面不会刷新(angular1.x 路由采用) 2.根据h5 pushState 和replaceState 修改url 时,页面不会刷新(react-router.vue-router) pushState/replaceState 执行时,url 会发生变化,但是浏览器并不会刷新,只有当前进或者后退触发时,页面才会刷新 pushState/replaceState

【Web API系列教材】1.3 — 实战:用ASP.NET Web API和Angular.js创建单页面应用程序(下)

练习2:创建SPA界面 在本练习中,你将首先创建Geek Quiz的web前端,使用AngularJS专注于单页面应用程序的交互.然后你将使用CSS3来执行丰富的动画和提供一个当从一个问题转换到另一个问题时切换上下文的可视化效果以加强用户体验. 任务1:使用AngularJS来创建SPA界面 在本任务中,你将使用AngularJS来实现Geek Quiz应用程序的客户端.AngularJS是一个开源的JavaScript框架,它能够搭配MVC以加强基于浏览器的应用程序,使其对于开发和测试都更加便

Oracle JET 单页面应用程序Router 使用(上)

单页面应用程序:使用一个进加载一次的网页,如果页面由于用户的交互而改变,则仅绘制更改的页面部分. 要创建单页面应用程序需要使用 oj.Router 的虚拟导航来支持,ojModule 用来响应页面的重新绘制. ojModule 仅用于分离的 view 和 viewMode ,使之与页面通过 Knockout绑定.另外,ojModule 可选,当不使用分离视图与模型时,可直接在元素上响应变化. 1.简单模型: 当选择 Chapter1 或其他时,将显示新内容,并且URL更改以反映用户在页面上当前的

快速了解SPA单页面应用

简要 SPA单页网页应用程序这个概念并不算新,早在2003年就已经有在讨论这个概念了,不过,单页应用这个词是到了2005年才有人提出使用,SPA的概念就和它的名字一样显而易懂,就是整个网站不再像传统的HTML网页一样,需要每做一个动作就更新一次网页,而是像传统的电脑软件一样,只变更显示的内容而不需变更整个网页!概念很简单,但是,事实上却有不少的问题要考虑. 理解单页面应用 简单来说SPA的网页只会有一个网页,而这个网页的设计方式要能够回应使用者所使用的各种装置并且复制使用者在电脑上使用软件的经验

spa单页面应用(angular)

本篇文章是对单页面的一个简单的基本逻辑操作,这个方法可以搭建基本的单页面的逻辑结构. 简单理解:单页面应用,锚点值切换,一个路由对应一个页面. 路由:此时会创建一个信息保存路由的信息,之后对页面a标签进行操作,会进入路由表中查找与之匹配的路由信息. ----html <div> <a href='#/news'>跳转到news</a> <a href='#/share'>跳转到share</a> <router-view></r

前端开发:单页面和多页面使用场景

一.单页面应用 只有一张Web页面的应用,是一种从Web服务器加载的富客户端,单页面跳转仅刷新局部资源 ,公共资源(js.css等)仅需加载一次,常用于PC端官网.购物等网站. 二.多页面应用(MultiPage Application,MPA) 多页面跳转刷新所有资源,每个公共资源(js.css等)需选择性重新加载,常用于 app 或 客户端等. 原文地址:https://blog.51cto.com/14535203/2436275

Vue系列(1):单页面应用程序

前言:关于页面上的知识点,如有侵权,请看 这里 . 关键词:SPA.单个 HTML 文件.全靠 JS 操作.Virtual DOM.hash/history api 路由跳转.ajax 响应.按需加载.MVVM SPA 我们先来看一下在百科上面的解释吧,emmmm,一般呢,我每次搜索一些不懂的词,都会习惯先去看百科里面的解释,反正我从来都不奢望能看懂,只是指望有个大概的框架的,哈哈~ "单页面应用(SPA:single-page application),就是只有一张Web页面的应用,是加载单个

说说你对 SPA 单页面的理解,它的优缺点分别是什么?

SPA( single-page application )仅在 Web 页面初始化时加载相应的 HTML.JavaScript 和 CSS. 一旦页> 面加载完成,SPA 不会因为用户的操作而进行页面的重新加载或跳转: 取而代之的是利用路由机制实现 > HTML 内容的变换,UI 与用户的交互,避免页面的重新加载. 优点:用户体验好.快,内容的改变不需要重新加载整个页面,避免了不必要的跳转和重复渲染:基于上面一点,SPA 相对对服务器压力小:前后端职责分离,架构清晰,前端进行交互逻辑,后端负