Blazor 模板化组件开发指南

翻译自 Waqas Anwar 2021年4月15日的文章 《A Developer’s Guide To Blazor Templated Components》 [1]

在我之前的一篇文章 Blazor 组件入门指南中,我介绍了组件参数,并向您展示了如何将数据作为参数传递给 Blazor 组件以定制化其功能。在这篇文章中,我将更进一步向您展示,如何将一个或多个 UI 模板作为参数传递给一个称之为模板化组件的不同类型的 Blazor 组件。

下载源码[2]

Blazor 模板化组件概述

Blazor 模板化组件是一种接受将一个或多个 UI 模板作为参数的组件。这有助于组件的可重用性,因为您只需要创建一次模板化组件,然后使用该组件的每个页面都可以提供其 UI 模板,模板化组件可以根据页面需求渲染此 UI 模板。

本文中的模板化组件示例包括:

  1. 一个允许用户指定表格表头、行和页脚模板的表格组件。

  2. 一个允许用户呈现具有相同外观和体验而具有不同内容的小部件组件。

  3. 一个允许用户指定一个模板来呈现项目符号或编号等列表项的列表组件。

  4. 一个允许用户以列表、网格或卡片视图来显示数据的列表组件。

当我们创建 Blazor 组件的一个参数时,我们通常将其类型指定为 stringint 或者其他内置 .NET 数据类型。为了创建一个模板化组件,我们需要创建类型为 RenderFragment 或 RenderFragment<T> 的组件参数。RenderFragment 允许我们提供一个可以由模板化组件渲染的 UI 内容片段(作为一个委托实现,将其内容写入到 RenderTreeBuilder)。

[Parameter]
public RenderFragment HeaderTemplate { get; set; }

RenderFragment<T> 更进一步,允许我们传入参数的类型 T,可以用它来自定义模板化组件的输出。

[Parameter]
public RenderFragment<T> RowTemplate { get; set; }

从一个实例开始

为了详细了解模板化组件,我决定构建一个 TableWidget 模板化组件,它允许我们自定义不同格式的表头、行和页脚。在创建第一个模板化组件之前,我们先来创建一个新的 Blazor Server 应用程序并添加其基本功能,以表格格式呈现一些数据。

在 Blazor Server 应用程序中创建一个 Data 文件夹,并在 Data 文件夹中添加以下两个模型类。

Product.cs

public class Product
{public int Id { get; set; }public string Title { get; set; }public decimal Price { get; set; }public int Quantity { get; set; }
}

Order.cs

public class Order
{public int Id { get; set; }public string OrderNo { get; set; }public DateTime OrderDate { get; set; }public string Status { get; set; }public decimal OrderTotal { get; set; }
}

在项目中创建一个 Services 文件夹,并在 Services 文件夹中添加如下的 IProductService 和 ProductService。在本教程中,我仅返回一些用于生成表格的模拟数据。

IProductService.cs

public interface IProductService
{List<Product> GetTopSellingProducts();
}

ProductService.cs

public class ProductService : IProductService
{public List<Product> GetTopSellingProducts(){return new List<Product>(){new Product(){Id = 1,Title = "Wireless Mouse",Price = 29.99m,Quantity = 3},new Product(){Id = 2,Title = "HP Headphone",Price = 79.99m,Quantity = 4},new Product(){Id = 3,Title = "Sony Keyboard",Price = 119.99m,Quantity = 5}};}
}

接下来,在同一 Services 文件夹中创建 IOrderService 和 OrderService 并添加一些用于生成表格的模拟订单数据。

IOrderService.cs

public interface IOrderService
{List<Order> GetLatestOrders();
}

OrderService.cs

public class OrderService : IOrderService
{public List<Order> GetLatestOrders(){return new List<Order>(){new Order(){Id = 1, OrderNo = "12345",OrderDate = DateTime.Today.AddDays(-2),Status = "Pending",OrderTotal = 399.99m},new Order(){Id = 2,OrderNo = "67890",OrderDate = DateTime.Today.AddDays(-5),Status = "Completed",OrderTotal = 199.99m},new Order(){Id = 3,OrderNo = "13579",OrderDate = DateTime.Today.AddDays(-7),Status = "Completed",OrderTotal = 249.99m}};}
}

我们需要使用依赖注入将上述服务注入到 Blazor 组件中,为此,我们需要在 Startup.cs 文件中注册上述服务。如果您想了解关于依赖注入的更多知识,可以阅读我的文章 A Step by Step Guide to ASP.NET Core Dependency Injection[3]

Startup.cs

public void ConfigureServices(IServiceCollection services)
{services.AddRazorPages();services.AddServerSideBlazor();services.AddSingleton<WeatherForecastService>();services.AddScoped<IOrderService, OrderService>();services.AddScoped<IProductService, ProductService>();
}

接下来,在项目 Pages 文件夹中创建 Blazor 组件 Dashboard.razor 及其对应的代码隐藏文件 Dashboard.razor.cs。如果您不熟悉 Blazor 组件及代码隐藏文件,请阅读我的文章 Blazor 组件入门指南。

组件的代码隐藏文件 Dashboard.razor.cs 中同时注入了 IOrderService 和 IProductService,然后我们将使用 GetLatestOrders 和 GetTopSellingProducts 方法来填充我们的本地 Orders 和 Products 列表。

Dashboard.razor.cs

public partial class Dashboard
{[Inject]private IOrderService OrderService { get; set; }[Inject]private IProductService ProductService { get; set; }private List<Order> Orders { get; set; }private List<Product> Products { get; set; }protected override void OnInitialized(){Orders = OrderService.GetLatestOrders();Products = ProductService.GetTopSellingProducts();}
}

Razor 组件视图文件将简单地在 Orders 和 Products 上运行 foreach 循环,并生成 HTML 表格。

@page "/dashboard"
<h1>Dashboard</h1>
<br />
<div class="row"><div class="col">@if (Orders != null){<table class="table table-striped table-bordered"><thead class="thead-dark"><tr><th scope="col">Order</th><th scope="col">Date</th><th scope="col">Status</th><th scope="col">Total</th></tr></thead><tbody>@foreach (var order in Orders){<tr><td>@order.OrderNo</td><td>@order.OrderDate.ToShortDateString()</td><td>@order.Status</td><td>@order.OrderTotal</td></tr>}</tbody></table>}</div><div class="col">@if (Products != null){<h3>Top Selling Products</h3><table class="table table-striped table-bordered"><thead class="thead-dark"><tr><th scope="col">Title</th><th scope="col">Price</th><th scope="col">Quantity</th></tr></thead><tbody>@foreach (var product in Products){<tr><td>@product.Title</td><td>@product.Price</td><td>@product.Quantity</td></tr>}</tbody></table>}</div>
</div>

此时如果您运行项目,将在页面上看到以下两个表格。

截至目前,我们尚没有创建任何模板化组件,但您会感觉到我们很快将需要一个,因为上面显示的订单和产品表格几乎都具有相同的外观和体验,并且我们在上面的 foreach 循环中复制了大量的 HTML 来生成这两张表格。一个好注意是,创建一个模板化组件,然后重用该组件来生成上述两张表格,并且仍然能够自定义它们显示的表头和数据行。让我们来创建我们的第一个模板化组件,命名为 TableWidget 组件。

创建 Blazor 模板化组件

在 Shared 文件夹中新建一个 Razor 组件 TableWidget.razor,并在其中添加以下代码:

TableWidget.razor

@typeparam TItem
<br />
<h3>@Title</h3>
<table class="table table-striped table-bordered"><thead class="thead-dark"><tr>@HeaderTemplate</tr></thead><tbody>@foreach (var item in Items){<tr>@RowTemplate(item)</tr>}</tbody><tfoot><tr>@FooterTemplate</tr></tfoot>
</table>
@code {[Parameter]public string Title { get; set; }[Parameter]public RenderFragment HeaderTemplate { get; set; }[Parameter]public RenderFragment<TItem> RowTemplate { get; set; }[Parameter]public RenderFragment FooterTemplate { get; set; }[Parameter]public IReadOnlyList<TItem> Items { get; set; }
}

我们的 TableWidget 组件包含以下三个模板:

[Parameter]
public RenderFragment HeaderTemplate { get; set; }[Parameter]
public RenderFragment<TItem> RowTemplate { get; set; }[Parameter]
public RenderFragment FooterTemplate { get; set; }

HeaderTemplate 允许用户在表格的表头中呈现任意 UI 模板。此模板用于在 thead 元素内渲染表格表头的单元格。

<thead class="thead-dark"><tr>@HeaderTemplate</tr>
</thead>

FooterTemplate 与 HeaderTemplate 类似,它允许用户在表格的页脚中呈现任意 UI 模板。此模板用于在 tfoot 元素内渲染表格页脚的单元格。

<tfoot><tr>@FooterTemplate</tr>
</tfoot>

RowTemplate 的类型为 RanderFragment<TItem>,它允许用户使用任意的 .NET 类型渲染 UI 模板。该类型不是固定的,而是使用组件顶部的 @typeparam 指令声明为一个泛型类型。

@typeparam TItem

我们还在组件中创建了一个 TItem 对象的集合,以便我们可以迭代该集合生成表格的行。

[Parameter]
public IReadOnlyList<TItem> Items { get; set; }

我们将要传入 UI 模板中的 TItem 类型的对象会使用以下 foreach 循环进行渲染。您很快就会看到这将如何帮助我们使用相同的 TableWidget 组件同时渲染产品和订单表格。

<tbody>@foreach (var item in Items){<tr>@RowTemplate(item)</tr>}
</tbody>

使用 Blazor 模板化组件的不同方式

现在是时候来实践一下我们的 TableWidget 组件了,我们可以通过不同的方式使用这个组件。用下面的 TableWidget 组件替换我们前面生成的 Recent Orders 表格。

<div class="col">@if (Orders != null){<TableWidget Title="Recent Orders" Items="Orders"><HeaderTemplate><th scope="col">Order</th><th scope="col">Date</th><th scope="col">Status</th><th scope="col">Total</th></HeaderTemplate><RowTemplate><td>@context.OrderNo</td><td>@context.OrderDate.ToShortDateString()</td><td>@context.Status</td><td>@context.OrderTotal</td></RowTemplate></TableWidget>}
</div>

在上面的代码片段中,Items 属性是使用我们的从服务获取的 Orders 列表进行初始化的。然后我们选择使用 HeaderTemplate 和 RowTemplate 来生成表格的表头和数据行。您可能在想 context 是从哪里来的?context 是一个隐式参数,所有类型为 RenderFragment<T> 的组件参数都可以使用。我们可以使用 context 访问我们正在处理对象的属性。在上面的示例中,context 将向模板提供订单信息。

如果此时您运行项目,会在页面上看到以下两个表格。现在,最近的订单(Recent Orders)表格是使用我们的 TableWidget 组件生成的了。

让我们重用 TableWidget 组件来生成热卖产品(Top Selling Products)表格。这一次,我们传递了 Products 列表给它,还指定了我们自己的 Context="product",这意味着现在我们可以使用 product 取代隐式参数 context 来访问产品的属性。

<div class="col">@if (Products != null){<TableWidget Title="Top Selling Products" Items="Products" Context="product"><HeaderTemplate><th scope="col">Title</th><th scope="col">Price</th><th scope="col">Quantity</th></HeaderTemplate><RowTemplate><td>@product.Title</td><td>@product.Price</td><td>@product.Quantity</td></RowTemplate></TableWidget>}
</div>

您还可以在模板级别指定上下文(Context),如下面的示例所示,其中将 Context="product" 添加到了 RowTemplate

<TableWidget Title="Top Selling Products" Items="Products"><HeaderTemplate><th scope="col">Title</th><th scope="col">Price</th><th scope="col">Quantity</th></HeaderTemplate><RowTemplate Context="product"><td>@product.Title</td><td>@product.Price</td><td>@product.Quantity</td></RowTemplate>
</TableWidget>

现在如果您运行该项目,您将看到页面上显示了以下两个表格,但是我们知道这次这两个表格是使用我们的模板化组件 TableWidget 渲染的。该示例清楚地演示了,同一个模板化组件可用于生成不同类型的 UI,并且可以根据我们的应用程序需求渲染不同类型的对象。

下面让我们通过另外两个例子重用一下我们的 TableWidget 组件,它们将显示同样的最近订单(Recent Orders)和热销产品(Top Selling Products),但布局略有改变。

<div class="row"><div class="col">@if (Orders != null){<TableWidget Title="Recent Orders" Items="Orders"><HeaderTemplate><th scope="col" colspan="2">Order Details</th><th scope="col">Status</th><th scope="col">Total</th></HeaderTemplate><RowTemplate Context="order"><td colspan="2"><b>Order No: </b>@order.OrderNo<br /><b>Order Date: </b>@order.OrderDate.ToShortDateString()</td><td>@order.Status</td><td>@order.OrderTotal</td></RowTemplate></TableWidget>}</div><div class="col">@if (Products != null){<TableWidget Title="Top Selling Products" Items="Products" TItem=”Product”><RowTemplate Context="product"><td><h2>@product.Title</h2><h4><b>@product.Price.ToString("C")</b></h4></td></RowTemplate><FooterTemplate><td class="text-right"><b>Last 30 Days</b></td></FooterTemplate></TableWidget>}</div>
</div>

在使用泛型类型组件时,会尽可能推断类型参数。不过,我们可以选择使用一个特性来显式指定类型,该特性的名称与类型参数相同,在上面的示例中是 TItem

此时如果您运行该项目,您将在页面上看到使用同一个 TableWidget 模板化组件渲染的全部四个表格。

创建通用模板化组件

我们的 TableWidget 组件很好,我们已见识了重用它的多个示例,但该组件的问题是它只生成了 HTML 表格。如果我们想要创建一个更通用的组件,可以重用它来生成任何类型的 UI(比如:表格、卡片、项目符号等)。我们可以通过从模板化组件中删除所有的标签来轻松地创建这样一个组件。让我们来创建一个通用的 ListWidget 组件,来实战练习一下这种组件。

在 Shared 文件夹中创建一个新的 ListWidget.razor 组件,并在其中添加以下代码。这次在组件中没有 HTML 标签,在 foreach 循环中仅有一个 ItemTemplate。这意味着我们可以使用这个 ListWidget 组件自由地生成任意类型的列表。

ListWidget.razor

@typeparam TItem@foreach (var item in Items)
{@ItemTemplate(item)
}@code {[Parameter]public RenderFragment<TItem> ItemTemplate { get; set; }[Parameter]public IReadOnlyList<TItem> Items { get; set; }
}

假如我们想要使用这个 ListWidget 组件生成 bootstrap 列表,那么我们可以使用下面的代码段来实现这一操作。

<ul class="list-group"><li class="list-group-item d-flex justify-content-between align-items-center active">Latest Products</li><ListWidget Items="Products" Context="product"><ItemTemplate><li class="list-group-item d-flex justify-content-between align-items-center">@product.Title<b>@product.Price.ToString("C")</b><span class="badge badge-primary badge-pill">@product.Quantity</span></li></ItemTemplate></ListWidget>
</ul>

运行该项目,您将看到以 bootstrap 列表方式生成的相同产品的列表。

现在,假设您有另一个页面,其中需要使用 div 和 a 标签以不同形式展示产品列表,那么您可以再次重用相同的 ListWidget 组件,这次生成如下标记:

<div class="list-group"><a class="list-group-item d-flex justify-content-between align-items-center active">Latest Products</a><ListWidget Items="Products" Context="product" TItem="Product"><ItemTemplate><a href="#" class="list-group-item list-group-item-action flex-column align-items-start"><div class="d-flex w-100 justify-content-between"><h5 class="mb-1"><b>@product.Title</b></h5><small class="text-muted">@product.Quantity units left</small></div><p class="mb-1">@product.Price.ToString("C")</p></a></ItemTemplate></ListWidget>
</div>

运行该项目,您将看到类似以下内容的输出。

总结

在本教程中,我概述了 Blazor 模板化组件,并创建了两种类型的模板化组件。然后,我们实践了几个重用 TableWidget 和 ListWidget 组件来生成不同类型标记的例子。我不得不承认,模板化组件是 Blazor 开发者工具箱中的一个很好的补充,我们可以使用这些组件创建一些令人惊叹的可重用组件。

相关阅读:

  • Blazor Server 和 WebAssembly 应用程序入门指南

  • Blazor 组件入门指南

  • Blazor 数据绑定开发指南

  • Blazor 事件处理开发指南

  • Blazor 组件之间使用 EventCallback 进行通信

  • Blazor 路由及导航开发指南

  • Blazor 模板化组件开发指南(本文)


相关链接:

  1. https://www.ezzylearning.net/tutorial/a-developers-guide-to-blazor-templated-components A Developer’s Guide To Blazor Templated Components ↩︎

  2. https://github.com/ezzylearning/BlazorTemplatedComponentDemo 下载源码 ↩︎

  3. https://www.ezzylearning.net/tutorial/a-step-by-step-guide-to-asp-net-core-dependency-injection A Step by Step Guide to ASP.NET Core Dependency Injection ↩︎

作者 :Waqas Anwar
译者 :技术译民
出品 :技术译站(https://ITTranslator.cn/)

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/299469.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

别太贪婪,这些技能能让你一辈子满足

全世界只有3.14 % 的人关注了青少年数学之旅在这个资讯丰富且易获取的时代&#xff0c;越来越多的人不愿意花时间阅读书籍&#xff0c;碎片化阅读成了主流。人们获取的东西多而杂&#xff0c;很难系统、全面。海量信息对人是冲击&#xff0c;更是诱惑。谁不想了解天下奇闻&…

纳尼???我JVM优化过头了,直接把异常信息优化没了?怎么办

你好呀&#xff0c;我是why。 你猜这次我又要写个啥没有卵用的知识点呢&#xff1f; 不好意思&#xff0c;问的稍微有点早了&#xff0c;啥提示都没给&#xff0c;咋猜呢&#xff0c;对吧&#xff1f; 先给你上个代码&#xff1a; public class ExceptionTest {public stati…

C# 读写ACCESS的OLE对象,演示图片与长文件的读写

网络上的读写OLE对象的代码是多&#xff0c;不过多是转载的&#xff0c;大部分人从来都没实际测试过&#xff0c;只是COPY来COPY去。我重来没看到一个真正可以运行的东东。没办法&#xff0c;只有自力更生&#xff0c;花了一点时间出了点研究成果&#xff0c;写到这里做个记录。…

WPF等待动画

WPF开发者QQ群&#xff1a; 340500857 | 微信群 -> 进入公众号主页 加入组织欢迎转发、分享、点赞、在看&#xff0c;谢谢~。 01—效果预览效果预览&#xff08;更多效果请下载源码体验&#xff09;&#xff1a;02—代码如下一、CycleLoading.cs 代码如下using System.Win…

假期别在家里要发霉了?可以靠他们度过无聊时光

全世界只有3.14 % 的人关注了青少年数学之旅在这个资讯丰富且易获取的时代&#xff0c;越来越多的人不愿意花时间阅读书籍&#xff0c;碎片化阅读成了主流。人们获取的东西多而杂&#xff0c;很难系统、全面。海量信息对人是冲击&#xff0c;更是诱惑。谁不想了解天下奇闻&…

cs6序列号 mac版photoshop_重磅!Parallels Desktop 16 M1版发布

Parallels 现已发布 Parallels Desktop 16 技术预览版&#xff0c;可以在搭载 M1 芯片的 Mac 电脑上运行。该公司表示&#xff0c;它创建了一个 “使用 Apple M1 Mac 芯片硬件辅助虚拟化的新虚拟化引擎”&#xff0c;允许用户在虚拟机中运行基于 Arm 的操作系统&#xff0c;例如…

华为二面!!!面试官直接问我Java中到底什么是NIO?这不是直接送分题???

华为二面&#xff01;&#xff01;&#xff01;面试官直接问我Java中到底什么是NIO&#xff1f;这不是直接送分题&#xff1f;&#xff1f;&#xff1f;什么是NIO缓冲区(Buffer)缓冲区类型获取缓冲区核心属性核心方法非直接缓冲区和直接缓冲区非直接缓冲区直接缓冲区通道(Chann…

Delphi中的容器类(3)

TBucketList和TObjectBucketList类 从Delphi6开始&#xff0c;VCL的Contnrs单元中又增加了两个新的容器类TBucketList和TObjectBucketList。TBucketList实际上也是一个简单基于哈希表的指针-指针对列表。接口定义如下&#xff1a; TBucketList class(TCustomBucketList)… pu…

一文读懂哈希和一致性哈希算法

哈希 Hash 算法介绍哈希算法也叫散列算法, 不过英文单词都是 Hash, 简单一句话概括, 就是可以把任意长度的输入信息通过算法变换成固定长度的输出信息, 输出信息也就是哈希值, 通常哈希值的格式是16进制或者是10进制, 比如下面的使用 md5 哈希算法的示例md5("123456"…

延迟开学?这些教育读书公众号可以帮助孩子学习! 你都关注了吗?

全世界只有3.14 % 的人关注了青少年数学之旅受新型冠状病毒疫情影响&#xff0c;日前&#xff0c;教育部印发《关于2020年春季学期延期开学的通知》。推迟开学时间&#xff0c;意味着寒假的延长。为此&#xff0c;小编精选这些优质的教育号和读书号帮助孩子学习&#xff01;理想…

go方法的深入探究(7.21增补)

2019独角兽企业重金招聘Python工程师标准>>> 1&#xff09;哪些类型可以有方法&#xff1a; 1&#xff09;只能对命名类型和命名类型的指针编写方法&#xff1b; 2&#xff09;不能对接口类型和接口类型的指针编写方法&#xff1b; 3&#xff09;只能在定义命名类型…

element文件上传有文件但是后台接收为空_程序员提高篇:大规格文件(G)是如何做分片优化的?...

作者&#xff1a;凹凸实验室 链接&#xff1a;https://juejin.im/post/5ebb4346e51d451ef53793ad整体思路第一步是结合项目背景&#xff0c;调研比较优化的解决方案。 文件上传失败是老生常谈的问题&#xff0c;常用方案是将一个大文件切片成多个小文件&#xff0c;并行请求接口…

你连简单的枚举类都不知道,还敢说自己会Java???滚出我的公司

枚举类型是Java 5中新增的特性&#xff0c;它是一种特殊的数据类型&#xff0c;之所以特殊是因为它既是一种类(class)类型却又比类类型多了些特殊的约束&#xff0c;但是这些约束的存在也造就了枚举类型的简洁性、安全性以及便捷性。当需要定义一组常量时&#xff0c;强烈建议使…

绝对硬核!万物有“理”,科学原来如此有趣!

▲ 点击查看假如在生活中&#xff0c;你不小心将生鸡蛋和熟鸡蛋混在一起了&#xff0c;那么此时你要如何分辨&#xff0c;哪个鸡蛋是生的&#xff0c;哪个是熟的呢&#xff1f;假若你曾学过力学&#xff0c;那你一定能够轻易的分辨这个生熟问题。我们把这两个鸡蛋放在桌上&…

微软输入法2010下载使用-IME2010下载使用

3年前&#xff0c;写过IME2007的安装和使用&#xff0c;在Office 2010 beta开放之后&#xff0c;觉得单独把ime2010单独开放出来比较适合Office 2003/2007的用户群。 1。 依然还是和上次的IME2007提取方式一样&#xff0c;先用7-zip解压Office 2007 beta的exe文件&#xff1a;由…

理论修炼之RabbitMQ,消息队列服务的稳健者

????欢迎点赞 &#xff1a;???? 收藏 ⭐留言 ???? 如有错误敬请指正&#xff0c;赐人玫瑰&#xff0c;手留余香&#xff01;????本文作者&#xff1a;由webmote 原创&#xff0c;首发于 【掘金】????作者格言&#xff1a;生活在于折腾&#xff0c;当你不折…

为什么年龄大了近视还增加_年龄明明一样大,为什么有人长得年轻,有人显老呢?...

台湾不老男神林志颖&#xff0c;始终是十几年前演偶像剧的脸。而德云社郭德纲与他是同龄人却饱经沧桑显得更加老相。这是一件让人哭笑不得的事&#xff0c;也被很多人编成段子。那么为什么有些人看起来年轻有些人却老的很快呢&#xff1f;哪一种更长寿呢&#xff1f;接下来让我…

利用Asp.net中的AJAX制作网页上自动选取开始日期及结束日期的用户自定义控件...

前段时间用过一个酒店入住预约网站&#xff0c;当你点击"入住时间"时会悬浮出一对并列的日历&#xff0c;然后点击左边的日历就能选择入住时间&#xff0c;点击右侧的日历就能自动得到离店时间&#xff0c;当时没有太留意是怎么实现的&#xff0c;现在在做项目时&…

【00】架构型

为什么80%的码农都做不了架构师&#xff1f;>>> 1、架构型&#xff08;archetype&#xff09; 一种形式&#xff0c;所有的东西或多或少地遵守。一种形式&#xff0c;属于同一类型的类都或多或少地遵守&#xff0c;包括属性、链接、方法、插入点、交互。 2、领域无…

SQL进阶提升(疑惑篇order by)-学习sql server2005 step by step(十一)

这篇主要发出两个疑惑&#xff0c;希望有兴趣的人解答&#xff0c;谢谢&#xff01; 1.newid()疑惑 1 create table tb (aa int,bb char(1)) 2 insert tb values(1,A) 3 insert tb values(1,B) 4 insert tb values(1,C) 5 insert tb values(1,D) 6 7 insert tb value…