使用ASP.NET Core和Sircl构建丰富的Web应用程序——第1部分

82 篇文章 3 订阅

目录

介绍

动态表单

Sircl简介

安装Sircl

Event-Actions

使用Sircl的动态表单

添加验证

结论

下次

引用


介绍

在本系列中,我们将了解如何仅使用ASP.NET CoreSircl轻松构建出色的交互式Web应用程序(通常需要大量JavaScript代码或用JavaScript框架编写的应用程序。

Sircl是一个开源的客户端库,它扩展了 HTML 以提供部分更新和常见行为,并可以轻松编写依赖于服务器端渲染的丰富应用程序。

在本系列的每一部分中,我们将介绍使用服务器端技术的富Web应用程序的典型编程问题,并了解如何使用SirclASP.NET Core中解决这个问题。

动态表单

对于第一部分,我选择了一个非常常见的问题:根据输入的数据动态更改输入表单。例如,网上商店的结帐页面要求您提供账单地址和送货地址。但是,如果两者相同,则只需输入一个。此表单可能如下所示:

https://www.codeproject.com/KB/Articles/5370424/Screenshot1.png?r=14cf6721-9fe6-48db-9394-471644e575fa

当用户选中递送到同一地址复选框时,递送地址字段将处于隐藏状态。

经典方法是使用JavaScript事件处理程序进行隐藏或显示。以下代码是使用jQuery编写的此类处理程序的示例:

$(function () {
    $("#IsSameAddress").on("change", function (e) {
        if ($("#IsSameAddress").prop("checked"))
            $("#DeliverySection").hide();
        else
            $("#DeliverySection").show();
    });
});

此外,如果表单的初始状态取决于现有数据,则必须对其初始状态进行编码,这通常在ASP.NET Razor视图中完成。例如,在DeliverySection元素上,如果地址是否相同的,我们将显示样式设置为none

<fieldset id="DeliverySection" style="@(Model.IsSameAddress ? "display: none;" : null)">
    <legend>Delivery address</legend>
    ...
</fieldset>

这可能是我们观点的完整代码:

@model CheckoutModel

@section Scripts
{
    <script>
        $(function () {
            $("#@Html.IdFor(m => m.IsSameAddress)").on("change", function (e) {
                if ($("#@Html.IdFor(m => m.IsSameAddress)").prop("checked")) {
                    $("#DeliverySection").hide();
                } else {
                    $("#DeliverySection").show();
                }
            });
        });
    </script>
}

<form method="post" asp-action="Next">
    <fieldset>
        <legend>Billing address</legend>
        <div class="mb-3">
            <label asp-for="BillingName" class="form-label">Name: *</label>
            <input type="text" class="form-control" asp-for="BillingName">
        </div>
        <div class="mb-3">
            <label asp-for="BillingAddress" class="form-label">Address</label>
            <textarea asp-for="BillingAddress" class="form-control" rows="3"></textarea>
        </div>
        <div class="form-check">
            <input class="form-check-input" type="checkbox" asp-for="IsSameAddress">
            <label class="form-check-label" asp-for="IsSameAddress">
                Deliver to same address
            </label>
        </div>
    </fieldset>

    <fieldset id="DeliverySection" style="@(Model.IsSameAddress ? "display: none;" : null)">
        <legend>Delivery address</legend>
        <div class="mb-3">
            <label asp-for="DeliveryName" class="form-label">Name: *</label>
            <input type="text" class="form-control" asp-for="DeliveryName">
        </div>
        <div class="mb-3">
            <label asp-for="DeliveryAddress" class="form-label">Address</label>
            <textarea asp-for="DeliveryAddress" class="form-control" rows="3"></textarea>
        </div>
    </fieldset>

    <button type="submit" class="btn btn-primary">Next</button>

</form>

不知何故,我们需要编写逻辑来确定DeliverySection是否要两次可见:我们将Razor代码和CSS语法结合起来(因为jQuery show/hidedisplay style属性一起使用),通过style属性来设置DeliverySection初始状态(可见或不可见)。

我们编写JavaScript/jQuery代码,以便在复选框更改时将状态从visible转换到hidden并转换回来。

这些代码不仅用不同的语言编写,具有不同的语义。这两段代码也放置在不同的位置。部分原因是最佳实践要求不要将转换代码作为内联事件处理程序1放置,还因为一段代码将放在触发元素(复选框)上,而另一段代码将放置在动态元素(部分)上。一段代码在服务器上运行,而另一段代码在客户端上运行。

在这个简单但常见的例子中,我们践踏了两种最佳实践:一次编写代码(DRYWET代码)2和争取高内聚和低耦合3通过将具有相同目的的代码放在不同的位置)。

此外,我们编写的代码是不可重用的,因为它与特定元素的IdCSS选择器交织在一起。下次需要类似的功能时,你的开发人员同事(当然不是你)会复制和粘贴代码,导致大量重复的代码难以维护。4

想象一下,以这种方式编写一个具有许多复杂用户界面元素依赖项的大型应用程序前端......

Sircl简介

Sircl是一个用JavaScript编写的免费开源库(您只需通过添加对脚本文件的引用来安装它),它使用额外的属性和类扩展了HTML。这些属性通常采用CSS选择器或URL作为值。无需学习新的语言或语法。

Sircl背后的想法是让渲染在服务器端完成,通过您的Razor视图(或PHP页面、JSP/JSF视图、NodeJS视图等,因为Sircl不依赖于您选择的服务器端技术)。它通过使用AJAX在幕后发送HTML来做到这一点。

但是,为了避免过多的服务器往返,Sircl还附带了一个广泛(且可扩展)的默认客户端行为库。

最终,Sircl允许您编写具有路由和深度链接支持的完整单页应用程序。

它带有BootstrapToastrSortableJS支持的扩展,这些库在构建丰富的Web应用程序时可能会派上用场。

您可以在 Sircl - Interactive web apps made easy 找到有关Sircl的所有信息。

安装Sircl

如果创建了“ASP.NET Core Web应用(模型-视图-控制器),则必须编辑Views\Shared文件夹中的_Layout.cshtml文件。

如果创建了“ASP.NET Core Web 应用(不带MVC部件),则使用的是RazorPages,并在Pages\Shared文件夹中找到_Layout.cshtml文件。

 _Layout.cshtml 文件中,添加以下代码行以添加Sircl捆绑的CSSSircl捆绑的Javascript文件。目前不需要Sircl Bootstrap文件,但由于Visual Studio模板已经引用了Bootstrap,我们稍后会使用它,因此不妨立即包含它:

<link href="https://cdn.jsdelivr.net/npm/sircl@2.3.7/sircl-bundled.min.css" rel="stylesheet" />
<script src="https://cdn.jsdelivr.net/npm/sircl@2.3.7/sircl-bundled.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/sircl@2.3.7/sircl-bootstrap5.min.js"></script>

在这种情况下,我们指的是CDN(内容分发网络)上的文件,因此您无需在本地下载文件。但你可以。找到在 Sircl - Get Started 上安装Sircl的不同方法。

Event-Actions

如前所述,Sircl使用其他属性和类扩展了HTML。这些属性和类中的大多数都是所谓的“Event-Actions”。它们是遵循命名架构<event>-<action>的属性或类。例如,onclick-show 属性在其元素上引发show事件(或冒泡)时,将执行click操作。要显示的对象或内容由属性的值决定,该属性是要显示的元素的CSS选择器。

举个例子:

<button type="button" onclick-show="#secret">Show my secret</button>
<div id="secret" hidden>I am a Gummy Bear</div>

您可以在已安装SirclCodePen中试用此功能:https://codepen.io/codetuner-the-lessful/pen/VwgwNWj

Event-Actions的命名使它们易于记忆和猜测。我相信你能猜到onclick-hideonclick-enableonclick-addclass做什么。

或者要考虑onchange-hideonsubmit-disable或者onhover-show

但回到我们的案例。在JavaScript代码中,我们监听了change事件。我们可以使用onchange-show或者onchange-hide Event-Actions。但是其中的哪一个,我们如何知道复选框是否被选中?

因此,我们宁愿需要onchecked-*onunchecked-*事件处理程序。

坏消息是不幸的是没有onchecked-show-hide Event-Action

好消息是,还有更好的!对于我们的情况,我们最好使用ifchecked-*ifunchecked-* Event-Actionsif前缀表示在事件发生时执行操作,但也在初始化时(加载页面时)执行操作,这意味着我们将能够将两段代码替换为单个Event-Action

此外,大多数ifchecked-* Event-Action都是双向的:当元素未选中时,它们会执行反向操作。而这正是我们在这里所需要的。

你能猜出我们将使用的Event-Action的名称吗?

事件操作记录在 Sircl - Event-Actions

使用Sircl的动态表单

我们现在已准备好更新我们的网页,以使用Sircl实现动态行为。

我们已经安装了Sircl并且知道什么是Event-Actions,因此我们可以开始更新我们的视图:

  1. 删除整个Scripts部分。
  2. 删除DeliverySection元素上的style属性。
  3. IsSameAddress checkbox元素添加以下属性:

ifchecked-hide="#DeliverySection"

就是这样!我们删除了所有过程性JavaScript代码,并摆脱了当两个地址相同时DeliverySection隐藏的双重规范。取而代之的是,我们有一个由HTML属性和CSS选择器组成的声明性规范。

为了获得更流畅的体验,请将该animate类添加到DeliverySection元素(显示和隐藏的元素),这将使显示和隐藏变得生动(初始呈现时除外)。

我将了解完整的代码。但首先还有一件事。

添加验证

当两个地址不同时,它们可能都是必需的。如果它们都相同,则只需要帐单地址。

基本上,当它们可见时,所有四个输入字段都是必需的。我们可以使用HTML验证并在四个字段上添加一个required属性。

但是,字段不可见的事实并不意味着其required属性将被忽略。如果未输入收货地址,则提交表单将失败,即使用户检查该表单与帐单地址相同...

在使用JavaScript代码的第一个版本中,我们可以添加代码来删除required属性,然后将它们放回原处,具体取决于是否选中该复选框。在JavaScript中,您可以动态添加、删除或更改属性和标签。

Sircl行为无法更改文档(添加或删除属性或标签),而无需往返到服务器。Sircl依靠服务器来构建HTML代码,并且在客户端修改HTML 代码的能力非常有限。

但是,这里还有另一种选择。在拥有required属性的同时,我们可以禁用输入元素(或实际上一次禁用整个字段集)。因为当输入元素(或其父字段集)被禁用时,HTML验证属性(包括required属性)将被忽略。

事实上,禁用元素更适合这种情况,因为其值(如果有一些)不会随表单一起提交,因此会产生副作用。

因此,只要我们将以下Event-Action属性添加到复选框中,我们就可以安全地标记所需的所有输入元素:

ifchecked-disable="#DeliverySection"

完整代码现在如下所示:

@model CheckoutModel

<form method="post" asp-action="Next">
    <fieldset>
        <legend>Billing address</legend>
        <div class="mb-3">
            <label asp-for="BillingName" class="form-label">Name: *</label>
            <input type="text" class="form-control" asp-for="BillingName" required>
        </div>
        <div class="mb-3">
            <label asp-for="BillingAddress" class="form-label">Address</label>
            <textarea asp-for="BillingAddress" class="form-control" rows="3" required>
            </textarea>
        </div>

        <div class="form-check">
            <input class="form-check-input" type="checkbox" asp-for="IsSameAddress"
                   ifchecked-hide="#DeliverySection"
                   ifchecked-disable="#DeliverySection">
            <label class="form-check-label" asp-for="IsSameAddress">
                Deliver to same address
            </label>
        </div>

    </fieldset>

    <fieldset id="DeliverySection" class="animate" hidden>
        <legend>Delivery address</legend>
        <div class="mb-3">
            <label asp-for="DeliveryName" class="form-label">Name: *</label>
            <input type="text" class="form-control" asp-for="DeliveryName" required>
        </div>
        <div class="mb-3">
            <label asp-for="DeliveryAddress" class="form-label">Address</label>
            <textarea asp-for="DeliveryAddress" class="form-control" rows="3" required>
            </textarea>
        </div>
    </fieldset>

    <button type="submit" class="btn btn-primary">Next</button>

</form>

您可能会注意到,我将DeliverySection标记为最初隐藏。由于Sircl Event-Actions是在渲染已经开始时在客户端上运行的,因此如果没有隐藏属性,如果最初选中该复选框,该部分将在几分之一秒内可见。相反,如果最初未选中该复选框,则隐藏属性将导致交付部分在几分之一秒后出现,但这通常不会引起干扰。

此示例的完整代码(包括控制器和模型)可以从本文顶部的链接下载。

结论

引入Sircl的最终结果是,我们可以用更少甚至没有JavaScript代码来编写我们的动态表单,保持动态行为,并用任何网页设计师都可以理解的简单声明性属性替换过程代码。

我们不必更改控制器代码或模型。我们也不必以不同的方式编写视图。

下次

下一篇文章中,我将介绍更多使用客户端行为和服务器端呈现的动态表单和页面的Sircl功能。我们还将看到如何处理拖放,使用Bootstrap模式或原生HTML5对话框以及编写单页应用程序。全部在ASP.NET Core中,带有Sircl,没有JavaScript代码。

引用

1 JavaScript security: Vulnerabilities and best practices · Raygun Blog
JavaScript代码甚至不应该在视图内的Scripts部分中,而应该在单独的文件中,甚至离相关元素更远。
2https://en.wikipedia.org/wiki/Don%27t_repeat_yourself
“DRY
原则被表述为每一项知识都必须在一个系统中具有单一的、明确的、权威的表示
3oop - What does 'low in coupling and high in cohesion' mean - Stack Overflow
“......
相关代码应该彼此靠近......“
4 https://en.wikipedia.org/wiki/Copy-and-paste_programming

https://www.codeproject.com/Articles/5370424/Build-Rich-Web-Apps-with-ASP-NET-Core-and-Sircl-3

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值