提交 bf22f17b 编写于 作者: L luweiping

add bbapp

上级 ce6e5187
# To learn more about .editorconfig see https://aka.ms/editorconfigdocs
###############################
# Core EditorConfig Options #
###############################
root = true
# All files
[*]
indent_style = space
charset = utf-8
trim_trailing_whitespace = true
insert_final_newline = true
# Code files
[*.{cs,csx,vb,vbx}]
indent_size = 4
[*.{cs,css,js,json,*html,razor,txt,log}]
charset = utf-8-bom
[*.{xml,config,*proj,nuspec,props,resx,targets,yml,tasks}]
indent_size = 2
# Xml config files
[*.{props,targets,ruleset,config,nuspec,resx,vsixmanifest,vsct}]
indent_size = 2
[*.json]
indent_size = 2
[*.{ps1,psm1}]
indent_size = 4
[*.sh]
indent_size = 4
end_of_line = lf
###############################
# .NET Coding Conventions #
###############################
[*.{cs,vb}]
# Organize usings
dotnet_sort_system_directives_first = false
# this. preferences
dotnet_style_qualification_for_field = false:silent
dotnet_style_qualification_for_property = false:silent
dotnet_style_qualification_for_method = false:silent
dotnet_style_qualification_for_event = false:silent
# Language keywords vs BCL types preferences
dotnet_style_predefined_type_for_locals_parameters_members = true:silent
dotnet_style_predefined_type_for_member_access = true:silent
# Parentheses preferences
dotnet_style_parentheses_in_arithmetic_binary_operators = always_for_clarity:silent
dotnet_style_parentheses_in_relational_binary_operators = always_for_clarity:silent
dotnet_style_parentheses_in_other_binary_operators = always_for_clarity:silent
dotnet_style_parentheses_in_other_operators = never_if_unnecessary:silent
# Modifier preferences
dotnet_style_require_accessibility_modifiers = for_non_interface_members:silent
dotnet_style_readonly_field = true:suggestion
# Expression-level preferences
dotnet_style_object_initializer = true:suggestion
dotnet_style_collection_initializer = true:suggestion
dotnet_style_explicit_tuple_names = true:suggestion
dotnet_style_null_propagation = true:suggestion
dotnet_style_coalesce_expression = true:suggestion
dotnet_style_prefer_is_null_check_over_reference_equality_method = true:silent
dotnet_prefer_inferred_tuple_names = true:suggestion
dotnet_prefer_inferred_anonymous_type_member_names = true:suggestion
dotnet_style_prefer_auto_properties = true:silent
dotnet_style_prefer_conditional_expression_over_assignment = true:silent
dotnet_style_prefer_conditional_expression_over_return = true:silent
###############################
# Naming Conventions #
###############################
# Style Definitions
dotnet_naming_style.pascal_case_style.capitalization = pascal_case
# Use PascalCase for constant fields
dotnet_naming_rule.constant_fields_should_be_pascal_case.severity = suggestion
dotnet_naming_rule.constant_fields_should_be_pascal_case.symbols = constant_fields
dotnet_naming_rule.constant_fields_should_be_pascal_case.style = pascal_case_style
dotnet_naming_symbols.constant_fields.applicable_kinds = field
dotnet_naming_symbols.constant_fields.applicable_accessibilities = *
dotnet_naming_symbols.constant_fields.required_modifiers = const
###############################
# C# Coding Conventions #
###############################
[*.cs]
# var preferences
csharp_style_var_for_built_in_types = true:silent
csharp_style_var_when_type_is_apparent = true:silent
csharp_style_var_elsewhere = true:silent
# Expression-bodied members
csharp_style_expression_bodied_methods = false:silent
csharp_style_expression_bodied_constructors = false:silent
csharp_style_expression_bodied_operators = false:silent
csharp_style_expression_bodied_properties = true:silent
csharp_style_expression_bodied_indexers = true:silent
csharp_style_expression_bodied_accessors = true:silent
# Pattern matching preferences
csharp_style_pattern_matching_over_is_with_cast_check = true:suggestion
csharp_style_pattern_matching_over_as_with_null_check = true:suggestion
# Null-checking preferences
csharp_style_throw_expression = true:suggestion
csharp_style_conditional_delegate_call = true:suggestion
# Modifier preferences
csharp_preferred_modifier_order = public,private,protected,internal,static,extern,new,virtual,abstract,sealed,override,readonly,unsafe,volatile,async:suggestion
# Expression-level preferences
csharp_prefer_braces = true:silent
csharp_style_deconstructed_variable_declaration = true:suggestion
csharp_prefer_simple_default_expression = true:suggestion
csharp_style_pattern_local_over_anonymous_function = true:suggestion
csharp_style_inlined_variable_declaration = true:suggestion
###############################
# C# Formatting Rules #
###############################
# New line preferences
csharp_new_line_before_open_brace = all
csharp_new_line_before_else = true
csharp_new_line_before_catch = true
csharp_new_line_before_finally = true
csharp_new_line_before_members_in_object_initializers = true
csharp_new_line_before_members_in_anonymous_types = true
csharp_new_line_between_query_expression_clauses = true
# Indentation preferences
csharp_indent_case_contents = true
csharp_indent_switch_labels = true
csharp_indent_labels = flush_left
# Space preferences
csharp_space_after_cast = false
csharp_space_after_keywords_in_control_flow_statements = true
csharp_space_between_method_call_parameter_list_parentheses = false
csharp_space_between_method_declaration_parameter_list_parentheses = false
csharp_space_between_parentheses = false
csharp_space_before_colon_in_inheritance_clause = true
csharp_space_after_colon_in_inheritance_clause = true
csharp_space_around_binary_operators = before_and_after
csharp_space_between_method_declaration_empty_parameter_list_parentheses = false
csharp_space_between_method_call_name_and_opening_parenthesis = false
csharp_space_between_method_call_empty_parameter_list_parentheses = false
# Wrapping preferences
csharp_preserve_single_line_statements = true
csharp_preserve_single_line_blocks = true
###############################
# VB Coding Conventions #
###############################
[*.vb]
# Modifier preferences
visual_basic_preferred_modifier_order = Partial,Default,Private,Protected,Public,Friend,NotOverridable,Overridable,MustOverride,Overloads,Overrides,MustInherit,NotInheritable,Static,Shared,Shadows,ReadOnly,WriteOnly,Dim,Const,WithEvents,Widening,Narrowing,Custom,Async:suggestion
[*.cs]
<Project Sdk="Microsoft.NET.Sdk.Web">
<PropertyGroup>
<TargetFramework>net5.0</TargetFramework>
</PropertyGroup>
<ItemGroup>
<SupportedPlatform Include="browser" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\BootstrapBlazorApp.Shared\BootstrapBlazorApp.Shared.csproj" />
</ItemGroup>
</Project>
@page
<h1 class="text-danger">Error.</h1>
<h2 class="text-danger">An error occurred while processing your request.</h2>
<h3>Development Mode</h3>
<p>
Swapping to <strong>Development</strong> environment will display more detailed information about the error that occurred.
</p>
<p>
<strong>The Development environment shouldn't be enabled for deployed applications.</strong>
It can result in displaying sensitive information from exceptions to end users.
For local debugging, enable the <strong>Development</strong> environment by setting the <strong>ASPNETCORE_ENVIRONMENT</strong> environment variable to <strong>Development</strong>
and restarting the app.
</p>
@page "/"
@namespace BootstrapBlazorApp.Server.Pages
@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers
@using BootstrapBlazorApp.Shared
@{
Layout = null;
}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Bootstrap Blazor Server App</title>
<base href="~/" />
<link rel="stylesheet" href="libs/font-awesome/css/font-awesome.min.css">
<link rel="stylesheet" href="_content/BootstrapBlazor/css/bootstrap.blazor.bundle.min.css">
<link rel="stylesheet" href="_content/BootstrapBlazorApp.Shared/css/site.css">
</head>
<body>
<app>
<component type="typeof(App)" render-mode="ServerPrerendered" />
</app>
<div id="blazor-error-ui">
<environment include="Staging,Production">
An error has occurred. This application may no longer respond until reloaded.
</environment>
<environment include="Development">
An unhandled exception has occurred. See browser dev tools for details.
</environment>
<a href="" class="reload">Reload</a>
<a class="dismiss">🗙</a>
</div>
<script src="_framework/blazor.server.js"></script>
<script src="_content/BootstrapBlazor/js/bootstrap.blazor.bundle.min.js"></script>
</body>
</html>
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Hosting;
namespace BootstrapBlazorApp.Server
{
public class Program
{
public static void Main(string[] args)
{
CreateHostBuilder(args).Build().Run();
}
public static IHostBuilder CreateHostBuilder(string[] args) =>
Host.CreateDefaultBuilder(args)
.ConfigureWebHostDefaults(webBuilder =>
{
webBuilder.UseStartup<Startup>();
});
}
}
{
"iisSettings": {
"windowsAuthentication": false,
"anonymousAuthentication": true,
"iisExpress": {
"applicationUrl": "http://localhost:53189",
"sslPort": 0
}
},
"profiles": {
"IIS Express": {
"commandName": "IISExpress",
"launchBrowser": true,
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
}
},
"BlazorApp1": {
"commandName": "Project",
"launchBrowser": true,
"applicationUrl": "http://localhost:5000",
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
}
}
}
}
using BootstrapBlazor.Components;
using BootstrapBlazorApp.Shared.Data;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Options;
namespace BootstrapBlazorApp.Server
{
public class Startup
{
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}
public IConfiguration Configuration { get; }
// This method gets called by the runtime. Use this method to add services to the container.
// For more information on how to configure your application, visit https://go.microsoft.com/fwlink/?LinkID=398940
public void ConfigureServices(IServiceCollection services)
{
services.AddRazorPages();
services.AddServerSideBlazor();
services.AddBootstrapBlazor(setupAction: options =>
{
options.AdditionalJsonAssemblies = new[] { GetType().Assembly };
});
services.AddRequestLocalization<IOptions<BootstrapBlazorOptions>>((localizerOption, blazorOption) =>
{
var supportedCultures = blazorOption.Value.GetSupportedCultures();
localizerOption.SupportedCultures = supportedCultures;
localizerOption.SupportedUICultures = supportedCultures;
});
services.AddSingleton<WeatherForecastService>();
// 增加 Table 数据服务操作类
services.AddTableDemoDataService();
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
else
{
app.UseExceptionHandler("/Error");
}
app.UseRequestLocalization(app.ApplicationServices.GetService<IOptions<RequestLocalizationOptions>>().Value);
app.UseStaticFiles();
app.UseRouting();
app.UseEndpoints(endpoints =>
{
endpoints.MapBlazorHub();
endpoints.MapFallbackToPage("/_Host");
});
}
}
}
@using BootstrapBlazor.Components
@using BootstrapBlazorApp.Server
@using BootstrapBlazorApp.Shared
@using BootstrapBlazorApp.Shared.Shared
@using Microsoft.AspNetCore.Authorization
@using Microsoft.AspNetCore.Components.Authorization
@using Microsoft.AspNetCore.Components.Forms
@using Microsoft.AspNetCore.Components.Routing
@using Microsoft.AspNetCore.Components.Web
@using Microsoft.JSInterop
@using System.ComponentModel
@using System.ComponentModel.DataAnnotations
@using System.Net.Http
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft": "Warning",
"Microsoft.Hosting.Lifetime": "Information"
}
},
"AllowedHosts": "*"
}
<Router AppAssembly="@typeof(MainLayout).Assembly" PreferExactMatches="@true">
<Found Context="routeData">
<RouteView RouteData="@routeData" DefaultLayout="@typeof(MainLayout)" />
</Found>
<NotFound>
<LayoutView Layout="@typeof(MainLayout)">
<p>Sorry, there's nothing at this address.</p>
</LayoutView>
</NotFound>
</Router>
using Microsoft.AspNetCore.Components;
using Microsoft.JSInterop;
using System;
using System.Threading.Tasks;
namespace BootstrapBlazorApp.Shared
{
/// <summary>
///
/// </summary>
public sealed partial class App
{
/// <summary>
///
/// </summary>
[Inject]
private IJSRuntime JSRuntime { get; set; }
/// <summary>
///
/// </summary>
/// <param name="firstRender"></param>
protected override async Task OnAfterRenderAsync(bool firstRender)
{
await base.OnAfterRenderAsync(firstRender);
if (firstRender && OperatingSystem.IsBrowser())
{
await JSRuntime.InvokeVoidAsync("$.loading");
}
}
}
}
<Project Sdk="Microsoft.NET.Sdk.Razor">
<PropertyGroup>
<TargetFramework>net5.0</TargetFramework>
</PropertyGroup>
<ItemGroup>
<SupportedPlatform Include="browser" />
</ItemGroup>
<ItemGroup>
<Content Remove="Locales\*.json" />
<EmbeddedResource Include="Locales\*.json" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="BootstrapBlazor" Version="5.0.34" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="Microsoft.AspNetCore.Components.Web" Version="5.0.7" />
</ItemGroup>
</Project>
using BootstrapBlazor.Components;
using BootstrapBlazorApp.Shared.Pages;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.DependencyInjection.Extensions;
using Microsoft.Extensions.Localization;
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
namespace BootstrapBlazorApp.Shared.Data
{
/// <summary>
/// BootstrapBlazor 服务扩展类
/// </summary>
public static class TableDemoDataServiceCollectionExtensions
{
/// <summary>
/// 增加 PetaPoco 数据库操作服务
/// </summary>
/// <param name="services"></param>
/// <returns></returns>
public static IServiceCollection AddTableDemoDataService(this IServiceCollection services)
{
services.AddScoped(typeof(IDataService<>), typeof(TableDemoDataService<>));
return services;
}
}
/// <summary>
/// 演示网站示例数据注入服务实现类
/// </summary>
internal class TableDemoDataService<TModel> : DataServiceBase<TModel> where TModel : class, new()
{
private static readonly ConcurrentDictionary<Type, Func<IEnumerable<TModel>, string, SortOrder, IEnumerable<TModel>>> SortLambdaCache = new();
private List<TModel> Items { get; set; }
private IStringLocalizer<Foo> Localizer { get; set; }
public TableDemoDataService(IStringLocalizer<Foo> localizer)
{
Localizer = localizer;
}
/// <summary>
/// 查询操作方法
/// </summary>
/// <param name="options"></param>
/// <returns></returns>
public override Task<QueryData<TModel>> QueryAsync(QueryPageOptions options)
{
// 此处代码实战中不可用,仅仅为演示而写防止数据全部被删除
if (Items == null || Items.Count == 0)
{
Items = Foo.GenerateFoo(Localizer).Cast<TModel>().ToList();
}
var items = Items.AsEnumerable();
var isSearched = false;
// 处理高级查询
if (options.SearchModel is Foo model)
{
if (!string.IsNullOrEmpty(model.Name)) items = items.Cast<Foo>().Where(item => item.Name?.Contains(model.Name, StringComparison.OrdinalIgnoreCase) ?? false).Cast<TModel>();
if (!string.IsNullOrEmpty(model.Address)) items = items.Cast<Foo>().Where(item => item.Address?.Contains(model.Address, StringComparison.OrdinalIgnoreCase) ?? false).Cast<TModel>();
isSearched = !string.IsNullOrEmpty(model.Name) || !string.IsNullOrEmpty(model.Address);
}
if (options.Searchs.Any())
{
// 针对 SearchText 进行模糊查询
items = items.Where(options.Searchs.GetFilterFunc<TModel>(FilterLogic.Or));
}
// 过滤
var isFiltered = false;
if (options.Filters.Any())
{
items = items.Where(options.Filters.GetFilterFunc<TModel>());
isFiltered = true;
}
// 排序
var isSorted = false;
if (!string.IsNullOrEmpty(options.SortName))
{
// 外部未进行排序,内部自动进行排序处理
var invoker = SortLambdaCache.GetOrAdd(typeof(Foo), key => LambdaExtensions.GetSortLambda<TModel>().Compile());
items = invoker(items, options.SortName, options.SortOrder);
isSorted = true;
}
var total = items.Count();
return Task.FromResult(new QueryData<TModel>()
{
Items = items.Skip((options.PageIndex - 1) * options.PageItems).Take(options.PageItems).ToList(),
TotalCount = total,
IsFiltered = isFiltered,
IsSorted = isSorted,
IsSearch = isSearched
});
}
/// <summary>
///
/// </summary>
/// <param name="model"></param>
/// <returns></returns>
public override Task<bool> SaveAsync(TModel model)
{
var ret = false;
if (model is Foo foo)
{
var item = Items?.FirstOrDefault(item =>
{
var f = item as Foo;
return f.Id == foo.Id;
});
if (item == null)
{
var id = Items!.Count + 1;
while (Items.FirstOrDefault(item => (item as Foo)!.Id == id) != null)
{
id++;
}
item = new Foo()
{
Id = id,
Name = foo.Name,
Address = foo.Address,
Complete = foo.Complete,
Count = foo.Count,
DateTime = foo.DateTime,
Education = foo.Education,
Hobby = foo.Hobby
} as TModel;
Items?.Add(item!);
}
else
{
var f = item as Foo;
f.Name = foo.Name;
f.Address = foo.Address;
f.Complete = foo.Complete;
f.Count = foo.Count;
f.DateTime = foo.DateTime;
f.Education = foo.Education;
f.Hobby = foo.Hobby;
}
ret = true;
}
return Task.FromResult(ret);
}
public override Task<bool> DeleteAsync(IEnumerable<TModel> models)
{
foreach (var model in models)
{
Items?.Remove(model);
}
return base.DeleteAsync(models);
}
}
}
using System;
namespace BootstrapBlazorApp.Shared.Data
{
/// <summary>
///
/// </summary>
public class WeatherForecast
{
/// <summary>
///
/// </summary>
public DateTime Date { get; set; }
/// <summary>
///
/// </summary>
public int TemperatureC { get; set; }
/// <summary>
///
/// </summary>
public int TemperatureF => 32 + (int)(TemperatureC / 0.5556);
/// <summary>
///
/// </summary>
public string Summary { get; set; } = "";
}
}
using System;
using System.Linq;
using System.Threading.Tasks;
namespace BootstrapBlazorApp.Shared.Data
{
/// <summary>
///
/// </summary>
public class WeatherForecastService
{
private static readonly string[] Summaries = new[]
{
"Freezing", "Bracing", "Chilly", "Cool", "Mild", "Warm", "Balmy", "Hot", "Sweltering", "Scorching"
};
/// <summary>
///
/// </summary>
/// <param name="startDate"></param>
/// <returns></returns>
public Task<WeatherForecast[]> GetForecastAsync(DateTime startDate)
{
var rng = new Random();
return Task.FromResult(Enumerable.Range(1, 5).Select(index => new WeatherForecast
{
Date = startDate.AddDays(index),
TemperatureC = rng.Next(-20, 55),
Summary = Summaries[rng.Next(Summaries.Length)]
}).ToArray());
}
}
}
{
"BootstrapBlazorApp.Shared.Pages.Foo": {
"Name": "Name",
"DateTime": "DateTime",
"Address": "Address",
"Count": "Count",
"Complete": "Complete",
"Education": "Education",
"Hobby": "Hobby",
"Name.Required": "{0} is required.",
"Address.Required": "{0} is required.",
"Education.Required": "{0} is required.",
"Hobby.Required": "{0} is required.",
"Name.PlaceHolder": "required",
"Hobbys": "Swimming,Climb,Shoot,Chess",
"Foo.Name": "Zhangsan {0}",
"Foo.Address": "Lane {0} of Jinshajiang Road, Putuo District, Shanghai",
"Foo.Address2": "Earth, China, Lane {0} of Jinshajiang Road, Putuo District, Shanghai. Here is an example of super long cell",
"Foo.BindValue": "BindValue"
},
"BootstrapBlazorApp.Shared.Pages.EnumEducation": {
"PlaceHolder": "Click to select ...",
"Primary": "Primary",
"Middel": "Middel"
}
}
{
"BootstrapBlazorApp.Shared.Pages.Foo": {
"Name": "姓名",
"DateTime": "日期",
"Address": "地址",
"Count": "数量",
"Complete": "是/否",
"Education": "学历",
"Hobby": "爱好",
"Name.Required": "{0}是必填项",
"Address.Required": "{0}是必填项",
"Education.Required": "{0}是必选项",
"Hobby.Required": "请选择一种{0}",
"Name.PlaceHolder": "不可为空",
"Hobbys": "游泳,登山,打球,下棋",
"Foo.Name": "张三 {0}",
"Foo.Address": "上海市普陀区金沙江路 {0} 弄",
"Foo.Address2": "地球、中国、上海市普陀区金沙江路 {0} 弄 这里是超长单元格示例",
"Foo.BindValue": "绑定值"
},
"BootstrapBlazorApp.Shared.Pages.EnumEducation": {
"PlaceHolder": "请选择 ...",
"Primary": "小学",
"Middel": "中学"
}
}
@page "/counter"
<h1>Counter</h1>
<p>Current count: @currentCount</p>
<button class="btn btn-primary" @onclick="IncrementCount">Click me</button>
@code {
private int currentCount = 0;
private void IncrementCount()
{
currentCount++;
}
}
@page "/fetchdata"
@using BootstrapBlazorApp.Shared.Data
@inject WeatherForecastService ForecastService
<h1>Weather forecast</h1>
<p>This component demonstrates fetching data from a service.</p>
@if (forecasts == null)
{
<p><em>Loading...</em></p>
}
else
{
<table class="table">
<thead>
<tr>
<th>Date</th>
<th>Temp. (C)</th>
<th>Temp. (F)</th>
<th>Summary</th>
</tr>
</thead>
<tbody>
@foreach (var forecast in forecasts)
{
<tr>
<td>@forecast.Date.ToShortDateString()</td>
<td>@forecast.TemperatureC</td>
<td>@forecast.TemperatureF</td>
<td>@forecast.Summary</td>
</tr>
}
</tbody>
</table>
}
@code {
private WeatherForecast[] forecasts;
protected override async Task OnInitializedAsync()
{
forecasts = await ForecastService.GetForecastAsync(DateTime.Now);
}
}
// Copyright (c) Argo Zhang (argo@163.com). All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
// Website: https://www.blazor.zone or https://argozhang.github.io/
using BootstrapBlazor.Components;
using Microsoft.Extensions.Localization;
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Linq;
namespace BootstrapBlazorApp.Shared.Pages
{
/// <summary>
///
/// </summary>
public class Foo
{
// 列头信息支持 Display DisplayName 两种标签
/// <summary>
///
/// </summary>
[Display(Name = "主键")]
[AutoGenerateColumn(Ignore = true)]
public int Id { get; set; }
/// <summary>
///
/// </summary>
[Required(ErrorMessage = "{0}不能为空")]
[AutoGenerateColumn(Order = 10, Filterable = true, Searchable = true)]
[Display(Name = "姓名")]
public string Name { get; set; }
/// <summary>
///
/// </summary>
[AutoGenerateColumn(Order = 1, FormatString = "yyyy-MM-dd", Width = 180)]
[Display(Name = "日期")]
public DateTime DateTime { get; set; }
/// <summary>
///
/// </summary>
[Display(Name = "地址")]
[Required(ErrorMessage = "{0}不能为空")]
[AutoGenerateColumn(Order = 20, Filterable = true, Searchable = true)]
public string Address { get; set; }
/// <summary>
///
/// </summary>
[Display(Name = "数量")]
[Required]
[AutoGenerateColumn(Order = 40, Sortable = true)]
public int Count { get; set; }
/// <summary>
///
/// </summary>
[Display(Name = "是/否")]
[AutoGenerateColumn(Order = 50, ComponentType = typeof(Switch))]
public bool Complete { get; set; }
/// <summary>
///
/// </summary>
[Required(ErrorMessage = "请选择学历")]
[Display(Name = "学历")]
[AutoGenerateColumn(Order = 60)]
public EnumEducation? Education { get; set; }
/// <summary>
///
/// </summary>
[Required(ErrorMessage = "请选择一种{0}")]
[Display(Name = "爱好")]
[AutoGenerateColumn(Order = 70)]
public IEnumerable<string> Hobby { get; set; } = new List<string>();
private static readonly Random random = new();
/// <summary>
///
/// </summary>
/// <param name="localizer"></param>
/// <returns></returns>
public static Foo Generate(IStringLocalizer<Foo> localizer) => new()
{
Id = 1,
Name = localizer["Foo.Name", "1000"],
DateTime = System.DateTime.Now,
Address = localizer["Foo.Address", $"{random.Next(1000, 2000)}"],
Count = random.Next(1, 100),
Complete = random.Next(1, 100) > 50,
Education = random.Next(1, 100) > 50 ? EnumEducation.Primary : EnumEducation.Middel
};
/// <summary>
///
/// </summary>
/// <returns></returns>
public static List<Foo> GenerateFoo(IStringLocalizer<Foo> localizer) => Enumerable.Range(1, 80).Select(i => new Foo()
{
Id = i,
Name = localizer["Foo.Name", $"{i:d4}"],
DateTime = System.DateTime.Now.AddDays(i - 1),
Address = localizer["Foo.Address", $"{random.Next(1000, 2000)}"],
Count = random.Next(1, 100),
Complete = random.Next(1, 100) > 50,
Education = random.Next(1, 100) > 50 ? EnumEducation.Primary : EnumEducation.Middel
}).ToList();
/// <summary>
///
/// </summary>
/// <returns></returns>
public static List<Foo> GenerateWrapFoo(IStringLocalizer<Foo> localizer) => Enumerable.Range(1, 4).Select(i => new Foo()
{
Id = i,
Name = localizer["Foo.Name", $"{i:d4}"],
DateTime = System.DateTime.Now.AddDays(i - 1),
Address = localizer["Foo.Address2", $"{random.Next(1000, 2000)}"],
Count = random.Next(1, 100),
Complete = random.Next(1, 100) > 50,
Education = random.Next(1, 100) > 50 ? EnumEducation.Primary : EnumEducation.Middel
}).ToList();
/// <summary>
///
/// </summary>
/// <returns></returns>
public static IEnumerable<SelectedItem> GenerateHobbys(IStringLocalizer<Foo> localizer) => localizer["Hobbys"].Value.Split(",").Select(i => new SelectedItem(i, i)).ToList();
}
/// <summary>
///
/// </summary>
public enum EnumEducation
{
/// <summary>
///
/// </summary>
[Display(Name = "小学")]
Primary,
/// <summary>
///
/// </summary>
[Display(Name = "中学")]
Middel
}
}
@page "/"
<h1>Hello, world!</h1>
Welcome to your new app.
<SurveyPrompt Title="How is Blazor working for you?" />
@page "/table"
<h1>Table</h1>
<Table TItem="Foo" IsPagination="true" PageItemsSource="@PageItemsSource"
IsStriped="true" IsBordered="true" ShowSkeleton="true" IsMultipleSelect="true"
ShowToolbar="true" ShowSearch="true" ShowExtendButtons="true"
UseInjectDataService="true" AutoGenerateColumns="true">
<TableColumns>
<TableColumn @bind-Field="@context.Hobby" Data="@Hobbys" />
</TableColumns>
</Table>
using BootstrapBlazor.Components;
using Microsoft.AspNetCore.Components;
using Microsoft.Extensions.Localization;
using System.Collections.Generic;
using System.Threading.Tasks;
namespace BootstrapBlazorApp.Shared.Pages
{
/// <summary>
///
/// </summary>
public partial class TableDemo : ComponentBase
{
[Inject]
private IStringLocalizer<Foo> Localizer { get; set; }
private IEnumerable<SelectedItem> Hobbys { get; set; }
/// <summary>
///
/// </summary>
protected override async Task OnInitializedAsync()
{
await base.OnInitializedAsync();
Hobbys = Foo.GenerateHobbys(Localizer);
}
/// <summary>
///
/// </summary>
private static IEnumerable<int> PageItemsSource => new int[] { 4, 10, 20 };
}
}
@inherits LayoutComponentBase
<Layout SideWidth="0" IsPage="true" ShowGotoTop="true" ShowCollapseBar="true"
IsFullSide="@IsFullSide" IsFixedHeader="@IsFixedHeader" IsFixedFooter="@IsFixedFooter" ShowFooter="@ShowFooter"
Menus="@Menus" UseTabSet="@UseTabSet" TabItemTextDictionary="@TabItemTextDictionary" AdditionalAssemblies="new[] { GetType().Assembly }" class="@Theme">
<Header>
<span class="ml-3 flex-sm-fill d-none d-sm-block">Bootstrap of Blazor</span>
<Widget></Widget>
<img src="_content/BootstrapBlazorApp.Shared/images/Argo.png" class="layout-avatar-right" />
<span class="mx-3 d-none d-sm-block">超级管理员</span>
<div class="layout-drawer" @onclick="@(e => IsOpen = !IsOpen)"><i class="fa fa-gears"></i></div>
</Header>
<Side>
<div class="layout-banner">
<img class="layout-logo" src="_content/BootstrapBlazorApp.Shared/images/brand.png" />
<div class="layout-title">
<span>后台管理</span>
</div>
</div>
<div class="layout-user">
<img class="layout-avatar" src="_content/BootstrapBlazorApp.Shared/images/Argo-C.png">
<div class="layout-title">
<span>管理员</span>
</div>
<div class="layout-user-state"></div>
</div>
</Side>
<Main>
<CascadingValue Value="this" IsFixed="true">
@Body
</CascadingValue>
</Main>
<Footer>
<div class="text-center flex-fill">
<a class="page-layout-demo-footer-link" href="https://gitee.com/LongbowEnterprise/BootstrapAdmin" target="_blank">Bootstrap Admin</a>
</div>
</Footer>
</Layout>
<Drawer Placement="Placement.Right" @bind-IsOpen="@IsOpen" IsBackdrop="true">
<div class="layout-drawer-body">
<div class="btn btn-info w-100" @onclick="@(e => IsOpen = false)">点击关闭</div>
<div class="page-layout-demo-option">
<p>布局调整</p>
<div class="row">
<div class="col-6">
<div class="layout-item @(IsFullSide ? "active d-flex" : "d-flex")" @onclick="@(e => IsFullSide = true)" data-toggle="tooltip" title="左右结构">
<div class="layout-left d-flex flex-column">
<div class="layout-left-header"></div>
<div class="layout-left-body flex-fill"></div>
</div>
<div class="layout-right d-flex flex-column flex-fill">
<div class="layout-right-header"></div>
<div class="layout-right-body flex-fill"></div>
<div class="layout-right-footer"></div>
</div>
</div>
</div>
<div class="col-6">
<div class="layout-item flex-column @(IsFullSide ? "d-flex" : "active d-flex")" @onclick="@(e => IsFullSide = false)" data-toggle="tooltip" title="上下结构">
<div class="layout-top">
</div>
<div class="layout-body d-flex flex-fill">
<div class="layout-left">
</div>
<div class="layout-right flex-fill">
</div>
</div>
<div class="layout-footer">
</div>
</div>
</div>
</div>
</div>
<div class="page-layout-demo-option">
<p>固定调整</p>
<div class="row">
<div class="col-6 d-flex align-items-center">
<Switch @bind-Value="@IsFixedHeader" OnColor="@Color.Success" OffColor="@Color.Secondary"></Switch>
</div>
<div class="col-6 text-right">
<span>固定页头</span>
</div>
</div>
<div class="row mt-3">
<div class="col-6 d-flex align-items-center">
<Switch @bind-Value="@IsFixedFooter" OnColor="@Color.Success" OffColor="@Color.Secondary"></Switch>
</div>
<div class="col-6 text-right">
<span>固定页脚</span>
</div>
</div>
<div class="row mt-3">
<div class="col-6 d-flex align-items-center">
<Switch @bind-Value="@ShowFooter" OnColor="@Color.Success" OffColor="@Color.Primary"></Switch>
</div>
<div class="col-6 text-right">
<span>显示页脚</span>
</div>
</div>
</div>
<div class="page-layout-demo-option">
<p>主题配色</p>
<div class="row">
<div class="col-2">
<span class="color color1" @onclick="@(e => Theme = "color1")"></span>
</div>
<div class="col-2">
<span class="color color2" @onclick="@(e => Theme = "color2")"></span>
</div>
<div class="col-2">
<span class="color color3" @onclick="@(e => Theme = "color3")"></span>
</div>
<div class="col-2">
<span class="color color4" @onclick="@(e => Theme = "color4")"></span>
</div>
<div class="col-2">
<span class="color color5" @onclick="@(e => Theme = "color5")"></span>
</div>
<div class="col-2">
<span class="color color6" @onclick="@(e => Theme = "color6")"></span>
</div>
</div>
</div>
<div class="page-layout-demo-option">
<p>更多设置</p>
<div class="row">
<div class="col-6 d-flex align-items-center">
<Switch @bind-Value="@UseTabSet" OnColor="@Color.Success" OffColor="@Color.Primary"></Switch>
</div>
<div class="col-6 text-right">
<span>@(UseTabSet ? "多标签" : "单页")</span>
</div>
</div>
</div>
</div>
</Drawer>
<Toast />
<Dialog />
<PopoverConfirm />
<Message />
<SweetAlert />
using BootstrapBlazor.Components;
using Microsoft.AspNetCore.Components.Routing;
using System.Collections.Generic;
using System.Threading.Tasks;
namespace BootstrapBlazorApp.Shared.Shared
{
/// <summary>
///
/// </summary>
public sealed partial class MainLayout
{
private bool UseTabSet { get; set; } = true;
private string Theme { get; set; } = "";
private bool IsOpen { get; set; }
private bool IsFixedHeader { get; set; } = true;
private bool IsFixedFooter { get; set; } = true;
private bool IsFullSide { get; set; } = true;
private bool ShowFooter { get; set; } = true;
private List<MenuItem> Menus { get; set; }
private Dictionary<string, string> TabItemTextDictionary { get; set; }
/// <summary>
/// OnInitialized 方法
/// </summary>
protected override async Task OnInitializedAsync()
{
await base.OnInitializedAsync();
// 模拟异步线程切换,正式代码中删除此行代码
await Task.Yield();
// 菜单获取可以通过数据库获取,此处为示例直接拼装的菜单集合
TabItemTextDictionary = new()
{
[""] = "Index"
};
Menus = GetIconSideMenuItems();
}
private static List<MenuItem> GetIconSideMenuItems()
{
var menus = new List<MenuItem>
{
new MenuItem() { Text = "返回组件库", Icon = "fa fa-fw fa-home", Url = "https://www.blazor.zone/components" },
new MenuItem() { Text = "Index", Icon = "fa fa-fw fa-fa", Url = "/" , Match = NavLinkMatch.All},
new MenuItem() { Text = "Counter", Icon = "fa fa-fw fa-check-square-o", Url = "/counter" },
new MenuItem() { Text = "FetchData", Icon = "fa fa-fw fa-database", Url = "fetchdata" },
new MenuItem() { Text = "Table", Icon = "fa fa-fw fa-table", Url = "table" }
};
return menus;
}
}
}
<div class="alert alert-secondary mt-4" role="alert">
<span class="oi oi-pencil mr-2" aria-hidden="true"></span>
<strong>@Title</strong>
<span class="text-nowrap">
Please take our
<a target="_blank" class="font-weight-bold" href="https://go.microsoft.com/fwlink/?linkid=2112271">brief survey</a>
</span>
and tell us what you think.
</div>
@code {
// Demonstrates how a parent component can supply parameters
[Parameter]
public string Title { get; set; }
}
<DropdownWidget class="text-right flex-fill px-3">
<DropdownWidgetItem Icon="fa fa-envelope-o" BadgeNumber="4">
<HeaderTemplate>
<span>您有 4 个未读消息</span>
</HeaderTemplate>
<BodyTemplate>
@for (var index = 0; index < 4; index++)
{
<a class="dropdown-item d-flex align-items-center" href="#" @onclick:preventDefault>
<div style="width: 40px; height: 40px;">
<Avatar Url="_content/BootstrapBlazorApp.Shared/images/argo-c.png" IsCircle="true" Size="Size.Small" />
</div>
<div class="ml-2">
<div class="d-flex position-relative">
<h4>Argo Zhang</h4>
<small><i class="fa fa-clock-o"></i> @(4 + index) mins</small>
</div>
<div class="text-truncate">Why not buy a new awesome theme?</div>
</div>
</a>
}
</BodyTemplate>
<FooterTemplate>
<a href="#" @onclick:preventDefault>查看所有消息</a>
</FooterTemplate>
</DropdownWidgetItem>
<DropdownWidgetItem Icon="fa fa-bell-o" BadgeNumber="10" HeaderColor="Color.Success" BadgeColor="Color.Warning">
<HeaderTemplate>
<span>您有 10 个未读通知</span>
</HeaderTemplate>
<BodyTemplate>
@for (var index = 0; index < 10; index++)
{
<a class="dropdown-item d-flex align-items-center" href="#" @onclick:preventDefault>
<i class="fa fa-users text-primary"></i>
<div class="ml-2">5 new members joined</div>
</a>
}
</BodyTemplate>
<FooterTemplate>
<a href="#" @onclick:preventDefault>查看所有通知</a>
</FooterTemplate>
</DropdownWidgetItem>
<DropdownWidgetItem Icon="fa fa-flag-o" BadgeNumber="9" HeaderColor="Color.Danger" BadgeColor="Color.Danger">
<HeaderTemplate>
<span>您有 3 个任务</span>
</HeaderTemplate>
<BodyTemplate>
<a href="#" class="dropdown-item" @onclick:preventDefault>
<h3 class="position-relative">
Design some buttons
<small class="pull-right">20%</small>
</h3>
<Progress IsAnimated="true" IsStriped="true" Value="20" Color="Color.Primary"></Progress>
</a>
<a href="#" class="dropdown-item" @onclick:preventDefault>
<h3 class="position-relative">
Create a nice theme
<small class="pull-right">40%</small>
</h3>
<Progress Value="40" Color="Color.Success"></Progress>
</a>
<a href="#" class="dropdown-item" @onclick:preventDefault>
<h3 class="position-relative">
Some task I need to do
<small class="pull-right">60%</small>
</h3>
<Progress Value="60" Color="Color.Danger"></Progress>
</a>
</BodyTemplate>
<FooterTemplate>
<a href="#" @onclick:preventDefault>查看所有任务</a>
</FooterTemplate>
</DropdownWidgetItem>
</DropdownWidget>
@using BootstrapBlazor.Components
@using BootstrapBlazorApp.Shared.Shared
@using Microsoft.AspNetCore.Authorization
@using Microsoft.AspNetCore.Components.Forms
@using Microsoft.AspNetCore.Components.Routing
@using Microsoft.AspNetCore.Components.Web
@using Microsoft.Extensions.Localization
@using Microsoft.JSInterop
@using System.ComponentModel
@using System.ComponentModel.DataAnnotations
@using System.Net.Http
@using System.Globalization
#blazor-error-ui {
background: lightyellow;
bottom: 0;
box-shadow: 0 -1px 2px rgba(0, 0, 0, 0.2);
display: none;
left: 0;
padding: 0.6rem 1.25rem 0.7rem 1.25rem;
position: fixed;
width: 100%;
z-index: 1080;
}
#blazor-error-ui .dismiss {
cursor: pointer;
position: absolute;
right: 0.75rem;
top: 0.5rem;
}
.page-layout-demo-footer-link {
color: #ebeef5;
}
.page-layout-demo-footer-link:hover {
color: #fff;
}
.page-layout-demo-option {
margin-top: 1.5rem;
border: 1px solid rgba(0,0,0,.125);
border-radius: 4px;
padding: 1.5rem 1rem 1rem 1rem;
position: relative;
}
.page-layout-demo-option > p {
position: absolute;
top: -10px;
padding: 0 0.5rem;
background: #fff;
}
.page-layout-demo-option .page-layout-demo-option-height {
display: flex;
align-items: center;
justify-content: space-between;
}
.page-layout-demo-option .tabs-body-content {
margin: 0 -1rem -2rem -1rem;
}
.layout-drawer {
padding: 13px;
margin-right: -1rem;
cursor: pointer;
}
.layout-drawer:hover {
background-color: #1893a7;
}
.layout-drawer-body {
padding: 1rem;
}
.layout-item {
cursor: pointer;
border: 2px solid #e9ecef;
padding: 4px;
border-radius: 4px;
height: 80px;
width: 120px;
transition: border .3s linear;
}
.layout-item:hover,
.layout-item.active {
border: 2px solid #28a745;
}
.layout-item .layout-left {
width: 30%;
}
.layout-item .layout-left .layout-left-header {
height: 16px;
background-color: #367fa9;
}
.layout-item .layout-left .layout-left-body,
.layout-item .layout-body .layout-left {
background-color: #2f4050;
}
.layout-item .layout-right .layout-right-header,
.layout-item .layout-top {
background-color: #17a2b8;
height: 16px;
}
.layout-item .layout-right .layout-right-footer,
.layout-item .layout-footer {
background-color: #5b6e84;
height: 12px;
}
.layout-item .layout-top,
.layout-item .layout-body,
.layout-item .layout-footer {
width: 100%;
}
.layout.is-page .layout-right,
.layout.is-page .layout-main {
background-color: #fff;
}
.color {
width: 1.5rem;
height: 1.5rem;
display: block;
cursor: pointer;
border: 2px solid #e9ecef;
border-radius: 4px;
transition: border .3s linear;
}
.color:hover {
border: 2px solid #28a745;
}
.color1,
.layout.is-page.color1 .layout-header {
background-color: #409eff;
}
.layout.is-page.color1 .layout-side .layout-banner {
background-color: #3e84d0
}
.layout.is-page.color1 .layout-side {
background-color: #212529;
color: #ebeef5;
}
.layout.is-page.color1 .layout-footer {
background-color: #343a40;
}
.layout.is-page.color1 .layout-header-bar {
background-color: #2b7cd0;
border-color: #014186;
}
.layout.is-page.color1 .layout-drawer:hover {
background-color: #3184dc;
}
.color2,
.layout.is-page.color2 .layout-header {
background-color: #28a745;
}
.layout.is-page.color2 .layout-side .layout-banner {
background-color: #24903d
}
.layout.is-page.color2 .layout-side {
background-color: #212529;
color: #ebeef5;
}
.layout.is-page.color2 .layout-footer {
background-color: #343a40;
}
.layout.is-page.color2 .layout-header-bar {
background-color: #258c3c;
border-color: #014186;
}
.layout.is-page.color2 .layout-drawer:hover {
background-color: #24903d;
}
.color3,
.layout.is-page.color3 .layout-header {
background-color: #e83e8c;
}
.layout.is-page.color3 .layout-side .layout-banner {
background-color: #c5417e
}
.layout.is-page.color3 .layout-side {
background-color: #212529;
color: #ebeef5;
}
.layout.is-page.color3 .layout-footer {
background-color: #343a40;
}
.layout.is-page.color3 .layout-header-bar {
background-color: #c73477;
border-color: #014186;
}
.layout.is-page.color3 .layout-drawer:hover {
background-color: #c5417e;
}
.color4,
.layout.is-page.color4 .layout-header {
background-color: #ffc107;
}
.layout.is-page.color4 .layout-side .layout-banner {
background-color: #e4af10
}
.layout.is-page.color4 .layout-side {
background-color: #212529;
color: #ebeef5;
}
.layout.is-page.color4 .layout-footer {
background-color: #343a40;
}
.layout.is-page.color4 .layout-header-bar {
background-color: #e2b221;
border-color: #014186;
}
.layout.is-page.color4 .layout-drawer:hover {
background-color: #e4af10;
}
.color5,
.layout.is-page.color5 .layout-header {
background-color: #17a2b8;
}
.color6,
.layout.is-page.color6 .layout-header {
background-color: #6610f2;
}
.layout.is-page.color6 .layout-side .layout-banner {
background-color: #4b0cb3
}
.layout.is-page.color6 .layout-side {
background-color: #212529;
color: #ebeef5;
}
.layout.is-page.color6 .layout-footer {
background-color: #343a40;
}
.layout.is-page.color6 .layout-header-bar {
background-color: #4b0ab5;
border-color: #014186;
}
.layout.is-page.color6 .layout-drawer:hover {
background-color: #4b0cb3;
}
.widget .dropdown-body h3 {
color: #666666;
font-size: 14px;
margin-bottom: 10px;
}
.widget .dropdown-body h4 {
color: #444444;
font-size: 15px;
margin: 0;
}
.widget .dropdown-body small {
color: #999999;
font-size: 10px;
position: absolute;
top: 0;
right: 0;
}
.widget .dropdown-item > div:not(.progress):last-child {
width: calc(100% - 40px);
}
.widget .dropdown-item {
padding: 0.5rem 1rem;
}
.widget .progress {
height: 7px;
}
.widget .dropdown-item.active,
.widget .dropdown-item:active {
color: inherit;
}
.widget .dropdown-item:not(:nth-of-type(odd)):active {
background-color: inherit;
}
<Project Sdk="Microsoft.NET.Sdk.BlazorWebAssembly">
<PropertyGroup>
<TargetFramework>net5.0</TargetFramework>
<ServiceWorkerAssetsManifest>service-worker-assets.js</ServiceWorkerAssetsManifest>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly" Version="5.0.6" />
<PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly.DevServer" Version="5.0.6" PrivateAssets="all" />
<PackageReference Include="System.Net.Http.Json" Version="5.0.0" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\BootstrapBlazorApp.Shared\BootstrapBlazorApp.Shared.csproj" />
</ItemGroup>
<ItemGroup>
<ServiceWorker Include="wwwroot\service-worker.js" PublishedContent="wwwroot\service-worker.published.js" />
</ItemGroup>
</Project>
using BootstrapBlazorApp.Shared;
using BootstrapBlazorApp.Shared.Data;
using Microsoft.AspNetCore.Components.WebAssembly.Hosting;
using Microsoft.Extensions.DependencyInjection;
using System;
using System.Net.Http;
using System.Threading.Tasks;
namespace BootstrapBlazorApp.WebAssembly
{
/// <summary>
///
/// </summary>
public class Program
{
/// <summary>
///
/// </summary>
/// <param name="args"></param>
/// <returns></returns>
public static async Task Main(string[] args)
{
var builder = WebAssemblyHostBuilder.CreateDefault(args);
builder.RootComponents.Add<App>("app");
builder.Services.AddTransient(sp => new HttpClient { BaseAddress = new Uri(builder.HostEnvironment.BaseAddress) });
// 增加 BootstrapBlazor 组件
builder.Services.AddBootstrapBlazor();
builder.Services.AddSingleton<WeatherForecastService>();
// 增加 Table 数据服务操作类
builder.Services.AddTableDemoDataService();
var host = builder.Build();
await host.RunAsync();
}
}
}
{
"iisSettings": {
"windowsAuthentication": false,
"anonymousAuthentication": true,
"iisExpress": {
"applicationUrl": "http://localhost:50855",
"sslPort": 0
}
},
"profiles": {
"IIS Express": {
"commandName": "IISExpress",
"launchBrowser": true,
"inspectUri": "{wsProtocol}://{url.hostname}:{url.port}/_framework/debug/ws-proxy?browser={browserInspectUri}",
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
}
},
"BootstrapBlazor.WebAssembly.ClientHost": {
"commandName": "Project",
"launchBrowser": true,
"inspectUri": "{wsProtocol}://{url.hostname}:{url.port}/_framework/debug/ws-proxy?browser={browserInspectUri}",
"applicationUrl": "http://localhost:5000",
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
}
}
}
}
@using BootstrapBlazor.Components
@using BootstrapBlazorApp.WebAssembly
@using BootstrapBlazorApp.Shared.Shared
@using Microsoft.AspNetCore.Components.Forms
@using Microsoft.AspNetCore.Components.Routing
@using Microsoft.AspNetCore.Components.Web
@using Microsoft.AspNetCore.Components.WebAssembly.Http
@using Microsoft.JSInterop
@using System.ComponentModel
@using System.ComponentModel.DataAnnotations
@using System.Net.Http
@using System.Net.Http.Json
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Bootstrap Blazor Wasm App</title>
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0, shrink-to-fit=no">
<meta content="bootstrap,blazor,wasm,webassembly,UI,netcore,web,assembly" name="Keywords">
<base href="/">
<link rel="icon" href="favicon.ico" type="image/x-icon">
<link rel="shortcut icon" href="favicon.ico" type="image/x-icon">
<link rel="apple-touch-icon" href="icon-512.png">
<link rel="manifest" href="manifest.json">
<link rel="stylesheet" href="libs/font-awesome/css/font-awesome.min.css">
<link rel="stylesheet" href="_content/BootstrapBlazor/css/bootstrap.blazor.bundle.min.css">
<link rel="stylesheet" href="_content/BootstrapBlazorApp.Shared/css/site.css">
<link rel="stylesheet" href="style/loading.css">
</head>
<body class="overflow-hidden">
<app></app>
<div class="loader" id="loading">
<div class="logo">
<div class="one common"></div>
<div class="two common"></div>
<div class="three common"></div>
<div class="four common"></div>
<div class="five common"></div>
<div class="six common"></div>
<div class="seven common"></div>
<div class="eight common"></div>
</div>
<div class="intro">
<img src="_content/BootstrapBlazorApp.Shared/images/brand.png" />
<span>精彩即将呈现</span>
</div>
<div class="bar">
<div class="progress"></div>
</div>
</div>
<div id="blazor-error-ui">
<environment include="Staging,Production">
An error has occurred. This application may no longer respond until reloaded.
</environment>
<environment include="Development">
An unhandled exception has occurred. See browser dev tools for details.
</environment>
<a href="" class="reload">Reload</a>
<a class="dismiss"><i class="fa fa-times"></i></a>
</div>
<script src="_framework/blazor.webassembly.js"></script>
<script src="_content/BootstrapBlazor/js/bootstrap.blazor.bundle.min.js"></script>
<script src="js/common.js"></script>
<script src="service-worker-register.js"></script>
</body>
</html>
(function ($) {
$.extend({
loading: function () {
var $loader = $("#loading");
if ($loader.length > 0) {
$loader.addClass("is-done");
var handler = window.setTimeout(function () {
window.clearTimeout(handler);
$loader.remove();
$('body').removeClass('overflow-hidden');
}, 300);
}
},
});
})(jQuery);
{
"name": "Bootstrap-Blazor",
"short_name": "Bootstrap-Blazor",
"start_url": "./",
"display": "standalone",
"background_color": "#ffffff",
"theme_color": "#03173d",
"icons": [
{
"src": "icon-512.png",
"type": "image/png",
"sizes": "512x512"
}
]
}
const serviceWorkerFileName = 'service-worker.js';
const swInstalledEvent = 'installed';
const staticCachePrefix = 'blazor-cache-v';
const updateAlertMessage = 'Update available. Reload the page when convenient.';
const blazorAssembly = 'BootstrapBlazor.Shared';
const blazorInstallMethod = 'PWAInstallable';
window.updateAvailable = new Promise(function (resolve, reject) {
if ('serviceWorker' in navigator) {
navigator.serviceWorker.register(serviceWorkerFileName)
.then(function (registration) {
console.log('Registration successful, scope is:', registration.scope);
registration.onupdatefound = () => {
const installingWorker = registration.installing;
installingWorker.onstatechange = () => {
switch (installingWorker.state) {
case swInstalledEvent:
if (navigator.serviceWorker.controller) {
resolve(true);
} else {
resolve(false);
}
break;
default:
}
};
};
})
.catch(error =>
console.log('Service worker registration failed, error:', error));
}
});
window['updateAvailable']
.then(isAvailable => {
if (isAvailable) {
alert(updateAlertMessage);
}
});
function showAddToHomeScreen() {
DotNet.invokeMethodAsync(blazorAssembly, blazorInstallMethod)
.then(function () { }, function (er) { setTimeout(showAddToHomeScreen, 1000); });
}
window.BlazorPWA = {
installPWA: function () {
if (window.PWADeferredPrompt) {
window.PWADeferredPrompt.prompt();
window.PWADeferredPrompt.userChoice
.then(function (choiceResult) {
window.PWADeferredPrompt = null;
});
}
}
};
window.addEventListener('beforeinstallprompt', function (e) {
// Prevent Chrome 67 and earlier from automatically showing the prompt
e.preventDefault();
// Stash the event so it can be triggered later.
window.PWADeferredPrompt = e;
showAddToHomeScreen();
});
\ No newline at end of file
// In development, always fetch from the network and do not enable offline support.
// This is because caching would make development more difficult (changes would not
// be reflected on the first load after each change).
self.addEventListener('fetch', () => { });
// Caution! Be sure you understand the caveats before publishing an application with
// offline support. See https://aka.ms/blazor-offline-considerations
self.importScripts('./service-worker-assets.js');
self.addEventListener('install', event => event.waitUntil(onInstall(event)));
self.addEventListener('activate', event => event.waitUntil(onActivate(event)));
self.addEventListener('fetch', event => event.respondWith(onFetch(event)));
const cacheNamePrefix = 'offline-cache-';
const cacheName = `${cacheNamePrefix}${self.assetsManifest.version}`;
const offlineAssetsInclude = [ /\.dll$/, /\.pdb$/, /\.wasm/, /\.html/, /\.js$/, /\.json$/, /\.css$/, /\.woff$/, /\.png$/, /\.jpe?g$/, /\.gif$/, /\.ico$/ ];
const offlineAssetsExclude = [ /^service-worker\.js$/ ];
async function onInstall(event) {
console.info('Service worker: Install');
// Fetch and cache all matching items from the assets manifest
const assetsRequests = self.assetsManifest.assets
.filter(asset => offlineAssetsInclude.some(pattern => pattern.test(asset.url)))
.filter(asset => !offlineAssetsExclude.some(pattern => pattern.test(asset.url)))
.map(asset => new Request(asset.url, { integrity: asset.hash }));
await caches.open(cacheName).then(cache => cache.addAll(assetsRequests));
}
async function onActivate(event) {
console.info('Service worker: Activate');
// Delete unused caches
const cacheKeys = await caches.keys();
await Promise.all(cacheKeys
.filter(key => key.startsWith(cacheNamePrefix) && key !== cacheName)
.map(key => caches.delete(key)));
}
async function onFetch(event) {
let cachedResponse = null;
if (event.request.method === 'GET') {
// For all navigation requests, try to serve index.html from cache
// If you need some URLs to be server-rendered, edit the following check to exclude those URLs
const shouldServeIndexHtml = event.request.mode === 'navigate';
const request = shouldServeIndexHtml ? 'index.html' : event.request;
const cache = await caches.open(cacheName);
cachedResponse = await cache.match(request);
}
return cachedResponse || fetch(event.request);
}
.loader {
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
background-color: #161B29;
transition: opacity .5s linear;
z-index: 2050;
display: flex;
flex-flow: column;
}
.loader.is-done {
opacity: 0;
}
.loader .logo {
width: 200px;
height: 200px;
position: relative;
margin: 0 auto;
}
@keyframes logo {
0%, 100% {
box-shadow: 1px 1px 25px 10px rgba(146, 148, 248, 0.4);
}
50% {
box-shadow: none;
}
}
.loader .intro {
width: 250px;
color: #fff;
font-size: 1.5rem;
text-align: center;
margin: 3rem auto;
display: inline-flex;
justify-content: center;
align-items: center;
padding: 0.5rem 1rem;
position: relative;
overflow: hidden;
border: 1px solid rgb(146, 148, 248);
animation: intro 3s linear infinite
}
@keyframes intro {
0%, 100% {
box-shadow: 0px 0px 25px 10px rgba(146, 148, 248, 0.4);
}
40%, 60% {
box-shadow: 0px 0px 25px 0px rgba(146, 148, 248, 0.4);
}
}
.loader .intro:before {
content: "";
position: absolute;
top: 0;
left: -100%;
width: 100%;
height: 100%;
background: linear-gradient( 120deg, transparent, rgba(146, 148, 248, 0.4), transparent );
animation: flash 2.5s linear infinite;
}
@keyframes flash {
0%, 100% {
}
10%, 90% {
left: 100%;
}
}
.loader .intro img {
border-radius: 3px;
width: 40px;
margin-right: 1rem;
}
.loader .intro span {
color: #fff;
animation: title 3s linear infinite;
}
@keyframes title {
0%, 100% {
color: #fff;
}
60% {
color: #666;
}
}
.loader .bar {
width: 50%;
height: 4px;
border-radius: 2px;
margin: auto;
background: #E645D0;
}
.loader .bar .progress {
width: 0%;
height: 4px;
margin: auto;
background: #17E1E6;
}
.loader .logo {
animation: logo 5s linear infinite;
-moz-animation: logo 5s linear infinite;
/* Firefox */
-webkit-animation: logo 5s linear infinite;
/* Safari and Chrome */
-o-animation: logo 5s linear infinite;
/* Opera */
}
@keyframes logo {
from {
transform: rotate(0deg);
}
to {
transform: rotate(-360deg);
}
}
.loader .progress {
animation: progress 12s linear;
-moz-animation: progress 12s linear;
/* Firefox */
-webkit-animation: progress 12s linear;
/* Safari and Chrome */
-o-animation: progress 12s linear;
/* Opera */
animation: progress 12s linear infinite;
}
@keyframes progress {
0%, 100% {
width: 0%;
background-color: #17e1e6;
}
50% {
width: 100%;
background-color: #28a745;
}
}
.loader .common {
height: 5vw;
max-height: 100%;
overflow: auto;
width: 2vw;
margin: auto;
max-width: 100%;
position: absolute;
border-radius: 0vw 10vw 0vw 10vw;
box-shadow: inset 0vw 0vw 0vw .1vw #E645D0, 0vw 0vw 1.5vw 0vw #E645D0;
}
.loader .one {
transform: rotate(45deg);
left: 0;
right: 0;
top: 0;
bottom: 7.5vw;
}
.loader .two {
transform: rotate(90deg);
left: 5.5vw;
right: 0;
top: 0;
bottom: 5.5vw;
}
.loader .three {
transform: rotate(135deg);
left: 7.5vw;
right: 0;
top: 0;
bottom: 0;
}
.loader .four {
transform: rotate(180deg);
left: 5.5vw;
right: 0;
top: 5.5vw;
bottom: 0;
}
.loader .five {
transform: rotate(225deg);
left: 0;
right: 0;
top: 7.5vw;
bottom: 0;
}
.loader .six {
transform: rotate(270deg);
left: 0;
right: 5.5vw;
top: 5.5vw;
bottom: 0;
}
.loader .seven {
transform: rotate(315deg);
left: 0;
right: 7.5vw;
top: 0;
bottom: 0;
}
.loader .eight {
transform: rotate(360deg);
left: 0;
right: 5.5vw;
top: 0;
bottom: 5.5vw;
}
.loader .one {
animation: one 1s ease infinite;
-moz-animation: one 1s ease infinite;
/* Firefox */
-webkit-animation: one 1s ease infinite;
/* Safari and Chrome */
-o-animation: one 1s ease infinite;
/* Opera */
}
@keyframes one {
0%, 100% {
}
50% {
box-shadow: inset 0vw 0vw 0vw .1vw #17E1E6, 0vw 0vw 1.5vw 0vw #17E1E6;
}
}
.loader .two {
animation: two 1s .125s ease infinite;
-moz-animation: two 1s .125s ease infinite;
/* Firefox */
-webkit-animation: two 1s .125s ease infinite;
/* Safari and Chrome */
-o-animation: two 1s .125s ease infinite;
/* Opera */
}
@keyframes two {
0%, 100% {
}
50% {
box-shadow: inset 0vw 0vw 0vw .1vw #17E1E6, 0vw 0vw 1.5vw 0vw #17E1E6;
}
}
.loader .three {
animation: three 1s .25s ease infinite;
-moz-animation: three 1s .25s ease infinite;
/* Firefox */
-webkit-animation: three 1s .25s ease infinite;
/* Safari and Chrome */
-o-animation: three 1s .25s ease infinite;
/* Opera */
}
@keyframes three {
0%, 100% {
}
50% {
background:;
box-shadow: inset 0vw 0vw 0vw .1vw #17E1E6, 0vw 0vw 1.5vw 0vw #17E1E6;
}
}
.loader .four {
animation: four 1s .375s ease infinite;
-moz-animation: four 1s .375s ease infinite;
/* Firefox */
-webkit-animation: four 1s .375s ease infinite;
/* Safari and Chrome */
-o-animation: four 1s .375s ease infinite;
/* Opera */
}
@keyframes four {
0%, 100% {
}
50% {
box-shadow: inset 0vw 0vw 0vw .1vw #17E1E6, 0vw 0vw 1.5vw 0vw #17E1E6;
}
}
.loader .five {
animation: five 1s .5s ease infinite;
-moz-animation: five 1s .5s ease infinite;
/* Firefox */
-webkit-animation: five 1s .5s ease infinite;
/* Safari and Chrome */
-o-animation: five 1s .5s ease infinite;
/* Opera */
}
@keyframes five {
0%, 100% {
}
50% {
box-shadow: inset 0vw 0vw 0vw .1vw #17E1E6, 0vw 0vw 1.5vw 0vw #17E1E6;
}
}
.loader .six {
animation: six 1s .625s ease infinite;
-moz-animation: six 1s .625s ease infinite;
/* Firefox */
-webkit-animation: six 1s .625s ease infinite;
/* Safari and Chrome */
-o-animation: six 1s .625s ease infinite;
/* Opera */
}
@keyframes six {
0%, 100% {
}
50% {
box-shadow: inset 0vw 0vw 0vw .1vw #17E1E6, 0vw 0vw 1.5vw 0vw #17E1E6;
}
}
.loader .seven {
animation: seven 1s .750s ease infinite;
-moz-animation: seven 1s .750s ease infinite;
/* Firefox */
-webkit-animation: seven 1s .750s ease infinite;
/* Safari and Chrome */
-o-animation: seven 1s .750s ease infinite;
/* Opera */
}
@keyframes seven {
0%, 100% {
}
50% {
box-shadow: inset 0vw 0vw 0vw .1vw #17E1E6, 0vw 0vw 1.5vw 0vw #17E1E6;
}
}
.loader .eight {
animation: eight 1s .875s ease infinite;
-moz-animation: eight 1s .875s ease infinite;
/* Firefox */
-webkit-animation: eight 1s .875s ease infinite;
/* Safari and Chrome */
-o-animation: eight 1s .875s ease infinite;
/* Opera */
}
@keyframes eight {
0%, 100% {
}
50% {
box-shadow: inset 0vw 0vw 0vw .1vw #17E1E6, 0vw 0vw 1.5vw 0vw #17E1E6;
}
}
@media (min-width: 768px) {
.loader {
padding-top: 8rem;
}
.loader .intro {
margin-top: 6rem;
}
}

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 16
VisualStudioVersion = 16.0.30621.155
MinimumVisualStudioVersion = 10.0.40219.1
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "BootstrapBlazorApp.Server", "BootstrapBlazorApp.Server\BootstrapBlazorApp.Server.csproj", "{DDC07B5C-7455-46A6-ADCD-FFF9023DE976}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "BootstrapBlazorApp.WebAssembly", "BootstrapBlazorApp.WebAssembly\BootstrapBlazorApp.WebAssembly.csproj", "{8F9288F6-E444-4B9F-8B8A-7C099980EE4D}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "BootstrapBlazorApp.Shared", "BootstrapBlazorApp.Shared\BootstrapBlazorApp.Shared.csproj", "{AB04595F-4692-4CA9-9D18-3F4C640AC028}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{DDC07B5C-7455-46A6-ADCD-FFF9023DE976}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{DDC07B5C-7455-46A6-ADCD-FFF9023DE976}.Debug|Any CPU.Build.0 = Debug|Any CPU
{DDC07B5C-7455-46A6-ADCD-FFF9023DE976}.Release|Any CPU.ActiveCfg = Release|Any CPU
{DDC07B5C-7455-46A6-ADCD-FFF9023DE976}.Release|Any CPU.Build.0 = Release|Any CPU
{8F9288F6-E444-4B9F-8B8A-7C099980EE4D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{8F9288F6-E444-4B9F-8B8A-7C099980EE4D}.Debug|Any CPU.Build.0 = Debug|Any CPU
{8F9288F6-E444-4B9F-8B8A-7C099980EE4D}.Release|Any CPU.ActiveCfg = Release|Any CPU
{8F9288F6-E444-4B9F-8B8A-7C099980EE4D}.Release|Any CPU.Build.0 = Release|Any CPU
{AB04595F-4692-4CA9-9D18-3F4C640AC028}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{AB04595F-4692-4CA9-9D18-3F4C640AC028}.Debug|Any CPU.Build.0 = Debug|Any CPU
{AB04595F-4692-4CA9-9D18-3F4C640AC028}.Release|Any CPU.ActiveCfg = Release|Any CPU
{AB04595F-4692-4CA9-9D18-3F4C640AC028}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {BFC48E48-51AB-48D3-8242-DC4823B978E4}
EndGlobalSection
EndGlobal
......@@ -5,6 +5,7 @@
</PropertyGroup>
<ItemGroup>
<PackageReference Include="BootstrapBlazor" Version="5.0.35-beta03" />
<PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly" Version="5.0.5" />
<PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly.DevServer" Version="5.0.5" PrivateAssets="all" />
<PackageReference Include="System.Net.Http.Json" Version="5.0.0" />
......
@page "/"
<h1>Hello, world!</h1>
Welcome to your new app.
<SurveyPrompt Title="How is Blazor working for you?" />
<h1>Dashboard!</h1>
......@@ -9,7 +9,7 @@
<ul class="nav flex-column">
<li class="nav-item px-3">
<NavLink class="nav-link" href="" Match="NavLinkMatch.All">
<span class="oi oi-home" aria-hidden="true"></span> Home
<span class="oi oi-home" aria-hidden="true"></span> Dashboard
</NavLink>
</li>
<li class="nav-item px-3">
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册