大家好,我是沙漠盡頭的狼。 Dotnet9網站回歸Blazor重構,訪問速度確實飛快,同時用上Blazor的交互能力,站長也同步添加了幾個線上工具,這篇文章分享下Blazor的重構過程,希望對大家網站開發時做技術選型有個參考。 ![](https://img1.dotnet9.com/2023/06 ...
大家好,我是沙漠盡頭的狼。
Dotnet9網站回歸Blazor重構,訪問速度確實飛快,同時用上Blazor的交互能力,站長也同步添加了幾個線上工具,這篇文章分享下Blazor的重構過程,希望對大家網站開發時做技術選型有個參考。
1. 先聊聊Razor Pages
上個版本網站前臺使用的Razor Pages開發,當時選擇這個技術棧主要是為了搜索引擎的SEO優化考慮。
關於MVC和Razor Pages哪個更優, 我們這裡只說說Razor Pages相對的優勢。
首先,Razor Pages相對於MVC來說,更加簡單和直觀。由於Razor Pages將視圖和處理邏輯封裝在同一個頁面中,開發人員可以更容易地理解和維護代碼。對於小型項目或者只有少量頁面的應用來說,Razor Pages可以提供更快的開發速度和更簡潔的代碼結構,這是站長當時從MVC重構成Razor Pages的主要選擇理由。
其次,Razor Pages在SEO(搜索引擎優化)方面具有一定的優勢。由於Razor Pages將視圖和處理邏輯封裝在同一個頁面中,搜索引擎可以更容易地理解和索引頁面的內容。這對於需要更好的搜索引擎排名的應用來說,是一個重要的考慮因素。
說Razor Pages優勢,那為啥現在又換Blazor了?因為Blazor可能又是更好的選擇了,我們接著說。
2. 關鍵聊聊Blazor
Blazor是一個新興的Web開發框架,它可以讓開發人員使用C#語言來編寫Web應用程式,而不必使用JavaScript,當然只能說儘量少用,完全不用也不太現實。相比於Razor Pages和MVC,Blazor提供了一種全新的開發模式,具有許多獨特的優勢和適用場景。
首先,Blazor提供了真正的前端開發體驗。傳統的Web開發中,前端開發人員需要使用JavaScript來處理頁面的交互和動態效果,而後端開發人員則負責處理業務邏輯和數據操作。這種分離的開發模式可能導致開發人員之間的溝通和協作問題。而Blazor使用C#語言來編寫前端代碼,使得前端和後端開發人員可以使用相同的語言和工具,更加高效地協作開發。
其次,Blazor提供了更好的性能和用戶體驗,Blazor提供了客戶端和服務端兩種模式(Blazor混合模式有機會我們再談):
- 客戶端模式:Blazor使用WebAssembly技術,在瀏覽器中直接運行編譯後的二進位代碼,可以實現接近原生應用的性能。
- 服務端模式:與傳統的基於HTTP請求的頁面刷新相比,Blazor使用SignalR連接來實現實時數據更新和雙向綁定,可以提供更快速和流暢的用戶體驗。
另外,Blazor還具有更好的可重用性和組件化開發。Blazor提供了豐富的組件庫和工具,可以幫助開發人員更快地構建出漂亮且功能強大的界面。開發人員可以將常用的UI組件封裝成可重用的組件,提高開發效率和代碼質量。
此外,Blazor還支持現代化的前端開發技術和工具。開發人員可以使用Blazor與現有的JavaScript庫和框架進行集成,如React、Vue.js等。
總之,Blazor對於Razor Pages和MVC來說是一個更好的選擇,特別是對於需要更好的前端開發體驗、更好的性能和用戶體驗以及更好的可重用性和組件化開發的項目來說。然而,選擇使用哪種開發模式還是要根據項目的具體需求和開發團隊的偏好來決定。無論選擇哪種模式,重要的是根據項目的實際情況做出合理的選擇,並且在開發過程中遵循良好的設計原則和最佳實踐。
3. 再聊聊為啥又用Blazor了?
站長在去年對網站前臺使用Blazor Server開發過一個版本,當時因為斷線重連體驗的問題,站長選擇用Razor Pages重構了。
這次站長回歸Blazor的轉折點在6月13號 - .NET 8 Preview 5發佈,VS2022預覽版也跟著出了Blazor Web App項目模板,各個技術群也討論瘋了,站長在Razor Pages中添加了Razor 組件嘗試,微軟確實牛逼,旨在使 Blazor 組件能夠滿足客戶端和伺服器端的所有 Web UI 需求。。
但目前該模式Razor組件無法交互,頁面還出現了重連置灰UI,索性直接用Blazor Server重構,經過幾天的奮戰,網站前臺已經用Blazor Server完全替換Razor Pages,煩人的重連也解決了,現在訪問網站飛快,不知道是不是錯覺,個人感覺很好。(重連問題參考微軟文檔【ASP.NET Core BlazorSignalR 指南】和Token佬寫的文章 【如何取消Blazor Server煩人的重新連接?】。)
Razor Pages(MVC)與Blazor都使用的Razor語法,所以理論上切換是無縫的,核心代碼改動不大,項目代碼文件結構對比看下麵截圖,不再贅述,有興趣看源碼吧,兩個版本代碼都在。
Razor Pages版工程結構 | Blazor Server版工程結構 |
4. Blazor的交互便利:帶來幾個線上工具
對於頁面的事件處理,使用Blazor就方便了,下麵是昨晚加的4個小工具:
有興趣的朋友可以點擊體驗:https://dotnet9.com/tools, 我們直接貼上4個小工具代碼,你可能會喜歡上Blazor的代碼風格。
4.1. JSON格式化
訪問地址:https://dotnet9.com/tools/jsonformatter
頁面代碼:
@page "/tools/jsonformatter"
@using System.Text.Json
<PageTitle>@_title</PageTitle>
<MApp>
<h2 style="margin-bottom: 30px; margin-top: 10px; text-align: center;">@_title</h2>
<div>
<MTextarea BackgroundColor="grey lighten-2" Solo
Color="orange orange-darken-4" TValue="string" @bind-Value="_inputJson"
Label="輸入Json" Rows="8" style="font-size:12px;" RowHeight="15" AutoGrow/>
</div>
<div>
<MButton Color="success" class="ma-2" OnClick="() => FormatJson(true)">格式化</MButton>
<MButton Color="lime" OnClick="() => FormatJson(false)">壓縮</MButton>
</div>
<div>
<MTextarea BackgroundColor="amber lighten-4" Solo
Color="orange orange-darken-4" TValue="string" @bind-Value="_formattedJson"
Label="格式化或壓縮後Json" Rows="8" style="font-size:12px;" RowHeight="15" AutoGrow/>
</div>
</MApp>
@code
{
private const string? _title = "工具箱-JSON格式化";
private string? _inputJson;
private string? _formattedJson;
private void FormatJson(bool writeIndented)
{
try
{
var jsonObject = JsonDocument.Parse(_inputJson).RootElement;
_formattedJson = JsonSerializer.Serialize(jsonObject, new JsonSerializerOptions { WriteIndented = writeIndented });
}
catch (JsonException)
{
_formattedJson = "無效的JSON格式";
}
}
}
4.2. 線上字元串編碼工具
訪問地址:https://dotnet9.com/tools/string-encoder
頁面代碼:
@page "/tools/string-encoder"
<PageTitle>@Title</PageTitle>
<MApp>
<h2 style="margin-bottom: 30px; margin-top: 10px; text-align: center;">@Title</h2>
<p>
<MTextarea BackgroundColor="grey lighten-2"
Color="cyan" Solo TValue="string" @bind-Value="_inputString"
Label="輸入字元串"/>
</p>
<p>
<MTextarea BackgroundColor="amber lighten-4" Solo
Color="orange orange-darken-4" TValue="string" @bind-Value="_encodedOrDecodeString"
Label="編/解碼結果"/>
</p>
<p>
<MButton OnClick="@Encode">編碼</MButton>
<MButton OnClick="@Decode">解碼</MButton>
<MButton OnClick="@Clear">清空</MButton>
</p>
</MApp>
@code {
private const string Title = "工具箱-線上字元串編碼工具";
private string? _inputString;
private string? _encodedOrDecodeString;
private void Encode()
{
_encodedOrDecodeString = System.Web.HttpUtility.UrlEncode(_inputString);
}
private void Decode()
{
_encodedOrDecodeString = System.Web.HttpUtility.UrlDecode(_inputString);
}
private void Clear()
{
_inputString = string.Empty;
_encodedOrDecodeString = string.Empty;
}
}
4.3. 倒計時
訪問地址:https://dotnet9.com/tools/countdown
頁面代碼:
@page "/tools/countdown"
<PageTitle>@Title</PageTitle>
<MApp>
<h2 style="margin-bottom: 30px; margin-top: 10px; text-align: center;">@Title</h2>
<p>
<MTextField Label="持續時間(秒)" Type="number" TValue="int" @bind-Value="@_duration"/>
</p>
<p>
<MButton Color="success" class="ma-2" OnClick="@StartCountdown" Disabled="@_isCountingDown">開始</MButton>
<MButton Color="pink" class="ma-2 white--text" OnClick="@PauseCountdown" Disabled="!_isCountingDown">暫停</MButton>
<MButton Color="deep-orange" class="ma-2 white--text" OnClick="@ResetCountdown" Disabled="!_isCountingDown">重置</MButton>
剩餘時間(秒):@_remainingTime
</p>
<div class="text-center">
<MProgressCircular Value="@_remainingTimePercent" Size="100" Width="15" Rotate="360" Color="teal">@_remainingTime</MProgressCircular>
</div>
</MApp>
@code {
private const string Title = "工具箱-倒計時";
private int _duration = 20;
private int _remainingTime;
private int _remainingTimePercent;
private bool _isCountingDown;
private bool _isPause;
private CancellationTokenSource? _countdownTokenSource;
private async Task StartCountdown()
{
if (_duration < 0)
{
_duration = 10;
}
if (_isCountingDown)
{
return;
}
_isCountingDown = true;
if (!_isPause || _remainingTime <= 0)
{
_remainingTime = _duration;
ChangeRemainingTimePercent();
}
_countdownTokenSource = new CancellationTokenSource();
await Countdown(_countdownTokenSource.Token);
}
private void PauseCountdown()
{
if (!_isCountingDown)
{
return;
}
_isCountingDown = false;
_isPause = true;
_countdownTokenSource?.Cancel();
}
private async void ResetCountdown()
{
_isPause = false;
if (_isCountingDown && _countdownTokenSource != null)
{
await _countdownTokenSource.CancelAsync();
}
_remainingTime = _duration;
_isCountingDown = false;
ChangeRemainingTimePercent();
}
private async Task Countdown(CancellationToken cancellationToken)
{
while (_remainingTime > 0)
{
await Task.Delay(1000, cancellationToken);
_remainingTime--;
ChangeRemainingTimePercent();
if (cancellationToken.IsCancellationRequested)
{
return;
}
}
_isCountingDown = false;
}
private async void ChangeRemainingTimePercent()
{
_remainingTimePercent = (int)(_remainingTime * 100.0 / _duration);
await InvokeAsync(StateHasChanged);
}
}
4.4. 時間戳轉換
訪問地址:https://dotnet9.com/tools/timestamp
站長原來寫過一篇,可以看這裡:使用Blazor做個簡單的時間戳線上轉換工具。
5. 總結
網站可能存在Bug,不,一定存在Bug,站長會一直重構迭代下去。
很高興將網站前臺重構後分享這個喜悅給大家,祝大家端午安康。
- 網站地址:https://dotnet9.com/
- 網站源碼:https://github.com/dotnet9/Dotnet9
- .NET版本: .NET 8.0.0-preview.5.23280.8