系列文章
- 基于 abp vNext 和 .NET Core 开发博客项目 - 使用 abp cli 搭建项目
- 基于 abp vNext 和 .NET Core 开发博客项目 - 给项目瘦身,让它跑起来
- 基于 abp vNext 和 .NET Core 开发博客项目 - 完善与美化,Swagger登场
- 基于 abp vNext 和 .NET Core 开发博客项目 - 数据访问和代码优先
- 基于 abp vNext 和 .NET Core 开发博客项目 - 自定义仓储之增删改查
- 基于 abp vNext 和 .NET Core 开发博客项目 - 统一规范API,包装返回模型
- 基于 abp vNext 和 .NET Core 开发博客项目 - 再说Swagger,分组、描述、小绿锁
- 基于 abp vNext 和 .NET Core 开发博客项目 - 接入GitHub,用JWT保护你的API
- 基于 abp vNext 和 .NET Core 开发博客项目 - 异常处理和日志记录
- 基于 abp vNext 和 .NET Core 开发博客项目 - 使用Redis缓存数据
- 基于 abp vNext 和 .NET Core 开发博客项目 - 集成Hangfire实现定时任务处理
- 基于 abp vNext 和 .NET Core 开发博客项目 - 用AutoMapper搞定对象映射
- 基于 abp vNext 和 .NET Core 开发博客项目 - 定时任务最佳实战(一)
- 基于 abp vNext 和 .NET Core 开发博客项目 - 定时任务最佳实战(二)
- 基于 abp vNext 和 .NET Core 开发博客项目 - 定时任务最佳实战(三)
- 基于 abp vNext 和 .NET Core 开发博客项目 - 博客接口实战篇(一)
- 基于 abp vNext 和 .NET Core 开发博客项目 - 博客接口实战篇(二)
- 基于 abp vNext 和 .NET Core 开发博客项目 - 博客接口实战篇(三)
- 基于 abp vNext 和 .NET Core 开发博客项目 - 博客接口实战篇(四)
- 基于 abp vNext 和 .NET Core 开发博客项目 - 博客接口实战篇(五)
- 基于 abp vNext 和 .NET Core 开发博客项目 - Blazor 实战系列(一)
- 基于 abp vNext 和 .NET Core 开发博客项目 - Blazor 实战系列(二)
- 基于 abp vNext 和 .NET Core 开发博客项目 - Blazor 实战系列(三)
- 基于 abp vNext 和 .NET Core 开发博客项目 - Blazor 实战系列(四)
- 基于 abp vNext 和 .NET Core 开发博客项目 - Blazor 实战系列(五)
- 基于 abp vNext 和 .NET Core 开发博客项目 - Blazor 实战系列(六)
- 基于 abp vNext 和 .NET Core 开发博客项目 - Blazor 实战系列(七)
- 基于 abp vNext 和 .NET Core 开发博客项目 - Blazor 实战系列(八)
- 基于 abp vNext 和 .NET Core 开发博客项目 - Blazor 实战系列(九)
- 基于 abp vNext 和 .NET Core 开发博客项目 - 终结篇之发布项目
前言
从今天开始将使用 Blazor 完成博客的前端开发,如果你不了解 Blazor ,建议你还是去微软官网学习学习基础知识。本篇不做普及,因为这是实战系列,重点是完成项目开发。
还有,在开始 Blazor 实战之前,建议动手完成之前的系列文章,这样更有连贯性,不至于懵圈。
因为我也是第一次使用 Blazor 开发项目,所以无法保证代码的最优性,如果有不对的地方,或者有更好的做法,欢迎大家指正,谢谢。
接下来,我将现学现做带来一个完整的博客项目,来吧,Just do it 。
我这里选择的是 Blazor WebAssembly,需要你有 .NET Core 3.1 的开发环境,并且你还要有 Visual Studio 2019 IDE。
给大家看看我的开发环境,终端工具是:Window Terminal ,配置一下用起来太爽了,五星强烈推荐。
搭建
Blazor WebAssembly 是一个单页应用框架,可用它通过 .NET 生成交互式客户端 Web 应用。 Blazor WebAssembly 使用开放的 Web 标准(没有插件或代码转换),适用于移动浏览器等各种新式 Web 浏览器。
…
不啰嗦了,直接开干吧,在项目中新建 Blazor Web 应用。
然后将项目设置为启动项目,Ctrl+F5 运行一下看看,官网默认示例我这里也懒得说了,直接进入主题吧。
改造
我这里使用的UI还是我目前博客的样式,你可以选择任意你喜欢的UI界面,这部分就随意了,不是本实战系列的重点,所以有关样式这些东西我就直接 Ctrl CV 了。
替换下面css代码到 wwwroot/css/app.css 中。
点击查看代码*,
*:after,
*:before {
-webkit-box-sizing: border-box;
-moz-box-sizing: border-box;
box-sizing: border-box;
}
html {
line-height: 1.15;
-webkit-text-size-adjust: 100%;
}
body {
margin: 0;
}
h1 {
font-size: 2em;
margin: 0.67em 0;
}
hr {
box-sizing: content-box;
height: 0;
overflow: visible;
}
pre {
font-family: monospace, monospace;
font-size: 1em;
}
a {
background-color: transparent;
}
abbr[title] {
border-bottom: none;
text-decoration: underline;
text-decoration: underline dotted;
}
b,
strong {
font-weight: bolder;
}
code,
kbd,
samp {
font-family: monospace, monospace;
font-size: 1em;
}
small {
font-size: 80%;
}
sub,
sup {
font-size: 75%;
line-height: 0;
position: relative;
vertical-align: baseline;
}
sub {
bottom: -0.25em;
}
sup {
top: -0.5em;
}
img {
border-style: none;
}
button,
input,
optgroup,
select,
textarea {
font-family: inherit;
font-size: 100%;
line-height: 1.15;
margin: 0;
}
button,
input {
overflow: visible;
}
button,
select {
text-transform: none;
}
button,
[type="button"],
[type="reset"],
[type="submit"] {
-webkit-appearance: button;
}
button::-moz-focus-inner,
[type="button"]::-moz-focus-inner,
[type="reset"]::-moz-focus-inner,
[type="submit"]::-moz-focus-inner {
border-style: none;
padding: 0;
}
button:-moz-focusring,
[type="button"]-moz-focusring,
[type="reset"]-moz-focusring,
[type="submit"]-moz-focusring {
outline: 1px dotted ButtonText;
}
fieldset {
padding: 0.35em 0.75em 0.625em;
}
legend {
box-sizing: border-box;
color: inherit;
display: table;
max-width: 100%;
padding: 0;
white-space: normal;
}
progress {
vertical-align: baseline;
}
textarea {
overflow: auto;
}
[type="checkbox"],
[type="radio"] {
box-sizing: border-box;
padding: 0;
}
[type="number"]::-webkit-inner-spin-button,
[type="number"]::-webkit-outer-spin-button {
height: auto;
}
[type="search"] {
-webkit-appearance: textfield;
outline-offset: -2px;
}
[type="search"]::-webkit-search-decoration {
-webkit-appearance: none;
}
::-webkit-file-upload-button {
-webkit-appearance: button;
font: inherit;
}
details {
display: block;
}
summary {
display: list-item;
}
template {
display: none;
}
[hidden] {
display: none;
}
@font-face {
font-family: 'Fira Code Medium';
src: url('https://static.meowv.com/fonts/FiraCode-Medium.woff2') format('woff2'), url("https://static.meowv.com/fonts/FiraCode-Medium.woff") format("woff");
font-weight: 500;
font-style: normal;
}
html {
font-family: 'Fira Code Medium', Microsoft Yahei, monospace;
overflow-x: hidden;
}
html::-webkit-scrollbar {
width: 5px;
height: 5px;
}
html::-webkit-scrollbar-thumb {
height: 20px;
background-color: #5A9600;
}
html::-webkit-scrollbar-thumb:hover {
background-color: #5A9600;
}
body {
font-size: 11pt;
font-weight: normal;
line-height: 2em;
background-color: #fff;
color: #161209;
transition: color 0.2s ease, border-color 0.2s ease, background 0.2s ease, opacity 0.2s ease;
}
body:before {
content: "";
background-repeat: no-repeat;
background-position: center;
opacity: 0.05;
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
z-index: -1;
}
body.dark-theme {
background-color: #292a2d;
color: #a9a9b3;
transition: color 0.2s ease, border-color 0.2s ease, background 0.2s ease, opacity 0.2s ease;
}
a {
color: #161209;
text-decoration: none;
transition: color 0.2s ease, border-color 0.2s ease, background 0.2s ease, opacity 0.2s ease;
cursor: pointer;
}
a:hover {
color: #5A9600;
text-decoration: none;
transition: color 0.2s ease, border-color 0.2s ease, background 0.2s ease, opacity 0.2s ease;
}
.dark-theme a {
color: #a9a9b3;
text-decoration: none;
transition: color 0.2s ease, border-color 0.2s ease, background 0.2s ease, opacity 0.2s ease;
}
.dark-theme a:hover {
color: #fff;
text-decoration: none;
transition: color 0.2s ease, border-color 0.2s ease, background 0.2s ease, opacity 0.2s ease;
}
.wrapper {
display: flex;
flex-direction: column;
min-height: 100vh;
width: 100%;
}
.navbar {
height: 4rem;
line-height: 4rem;
width: 100%;
}
.navbar .container {
width: auto;
max-width: 1200px;
text-align: center;
margin: 0 auto;
display: flex;
justify-content: space-between;
}
.main {
flex-grow: 1;
flex-shrink: 0;
flex-basis: auto;
}
.container {
padding-left: 1em;
padding-right: 1em;
}
.footer {
width: 100%;
text-align: center;
}
/*input css begin*/
* {
-webkit-tap-highlight-color: rgba(0, 0, 0, 0);
}
input[type="checkbox"],
input[type="radio"] {
display: none;
width: 0;
height: 0;
visibility: hidden;
}
input[type="checkbox"]:checked + label:after {
transition: all 0.3s ease-in;
}
input[type="checkbox"]:not(:checked) + label:after {
transition: all 0.3s ease-out;
}
input[type="checkbox"]:checked + label,
input[type="checkbox"]:not(:checked) + label {
transition: all 0.3s ease-in-out;
}
input[type="checkbox"]:checked + label:before,
input[type="checkbox"]:checked + label i:before,
input[type="checkbox"]:not(:checked) + label i:before,
input[type="checkbox"]:checked + label i:after,
input[type="checkbox"]:not(:checked) + label i:after,
input[type="checkbox"]:not(:checked) + label:before {
transition: all 0.3s ease-in-out;
}
input[type="radio"]:checked + label:after,
input[type="radio"]:not(:checked) + label:after {
transition: all 0.3s ease-in-out;
}
.switch_default + label {
background-color: #e6e6e6;
border-radius: 7px;
cursor: pointer;
display: inline-block;
height: 14px;
position: relative;
box-shadow: 0.2px 0.2px 1px 0.5px rgb(180, 180, 180);
width: 30px;
}
.switch_default + label:after