#showdev使用Blazor创建DEV&#039的离线页面
我在创建DEV的离线页面上发现了Ali Spittel的一篇有趣的帖子:
如何在DEV的离线页面上创建绘图交互
Ali Spittel·7月3日·4分钟阅读
#javascript #艺术 #showdev
鉴于我在过去使用WebAssembly做了一些实验,我决定在WebAssembly中对自己的实现进行一次破解,特别是对Blazor。
入门
警告:Blazor是一个使用.NET堆栈,特别是C#语言构建客户端Web应用程序的平台。它是高度实验性的,所以有可能事情会在写作时发生变化(我正在使用构建 3.0.0-preview6.19307.2
)。
首先,您需要按照Blazor的设置指南进行操作,一旦完成,您可以在您喜欢的编辑器中创建一个新项目(我使用的是VS Code)。
然后我删除了所有的样板代码 Pages
和 Shared
文件夹(除了任何 _Imports.razor
文件),Bootstrap来自 css
文件夹和 sample-data
。现在我们有一个完全空的Blazor项目。
创建我们的布局
我们需要做的第一件事是创建布局文件。与ASP.NET MVC一样,Blazor使用布局文件作为所有页面的基本模板(嗯,所有使用该布局的页面,您可以有多个布局)。所以,在中创建一个新文件 Shared
叫 MainLayout.razor
我们将定义它。鉴于我们希望它是全屏,它将非常简单:
@inherits LayoutComponentBase @Body
该文件继承了Blazor为布局提供的基类, LayoutComponentBase
这让我们可以访问 @Body
允许我们将页面内容放在我们想要的任何HTML中的属性。我们周围不需要任何东西,所以我们就这么说 @Body
在页面中。
创建我们的离线页面
是时候制作离线页了,我们先从创建一个新文件开始 Pages
文件夹,我们来称呼它 Offline.html
:
@page "/" Offline
这是我们的出发点,首先我们有 @page
该指令告诉Blazor这是一个我们可以导航到的页面,它将响应的URL是 "/"
。我们在那里有一些占位符HTML,接下来我们将替换它们。
启动画布
离线页面本质上是一个我们可以绘制的大画布,我们需要创建它,让我们更新 Offline.razor
使用canvas元素:
@page "/"
设置画布大小
我们需要将画布的大小设置为全屏,现在就是 0x0
,不理想。理想情况下,我们希望获得 innerWidth
和 innerHeight
浏览器,要做到这一点,我们需要使用Blazor的JavaScript互操作。
我们将快速创建一个新的JavaScript文件来交互(调用它 helper.js
并把它放进去 wwwroot
,也更新 index.html
在 wwwroot
参考它):
window.getWindowSize = () => { return { height: window.innerHeight, width: window.innerWidth }; };
接下来我们将创建一个C# struct
表示该数据(我添加了一个名为的文件 WindowSize.cs
进入项目根目录):
namespace Blazor.DevToOffline { public struct WindowSize { public long Height { get; set; } public long Width { get; set; } } }
最后,我们需要在Blazor组件中使用它:
@page "/" @inject IJSRuntime JsRuntime @code { WindowSize windowSize; protected override async Task OnInitAsync() { windowSize = await JsRuntime.InvokeAsync ("getWindowSize"); } }
这是一些代码添加,所以让我们分解它。
@inject IJSRuntime JsRuntime
这里我们使用依赖注入来注入 IJSRuntime
作为一个叫做的财产 JsRuntime
在我们的组件上。
接下来,我们将设置 height
和 width
的属性 元素到我们的实例的字段值
struct
,一个名为的实例 windowSize
。请注意 @
这告诉编译器这是指C#变量,而不是静态字符串。
@code { WindowSize windowSize; protected override async Task OnInitAsync() { windowSize = await JsRuntime.InvokeAsync<WindowSize>("getWindowSize"); } }
现在我们已经在代码块中添加了一个代码块。它包含变量 windowSize
(它是未初始化的,但它是一个结构,所以它有一个默认值)然后我们覆盖一个生命周期方法, OnInitAsync
,我们调用JavaScript来获取窗口大小并将其分配给我们的局部变量。
恭喜你,你现在有一个全屏画布 ?
接线活动
我们可能会出现我们的画布,但它还没有做任何事情,所以让我们通过添加一些事件处理程序来解决这个问题:
@page "/" @inject IJSRuntime JsRuntime
当您在Blazor中绑定事件时,您需要在事件名称前加上 @
, 喜欢 @onmousedown
,然后提供它在事件发生时调用的函数的名称,例如, @StartPaint
。这些函数的签名是返回a void
要么 Task
,取决于它是否异步。函数的参数需要是适当类型的事件参数,映射到DOM等价物(UIMouseEventArgs
, UIKeyboardEventArgs
等)。
注意:如果您将此与JavaScript参考实现进行比较,您会注意到我没有使用 touch
事件。这是因为,在我今天的实验中,Blazor中存在绑定触摸事件的错误。记住,这是预览
获取画布上下文
注意:我将讨论如何设置交互 来自Blazor,但在一个真实的应用程序中,你更可能想要使用BlazorExtensions / Canvas而不是自己动手。
由于我们需要使用画布的2D上下文,因此我们需要访问它。但是,这是一个JavaScript API,我们在C#/ WebAssembly,这将有点有趣。
最终,我们将在JavaScript中使用它并依赖Blazor的JavaScript互操作功能,所以仍然没有逃避编写一些JavaScript
让我们编写一个JavaScript模块来为我们提供一个API来处理:
((window) => { let canvasContextCache = {}; let getContext = (canvas) => { if (!canvasContextCache(canvas)) { canvasContextCache(canvas) = canvas.getContext('2d'); } return canvasContextCache(canvas); }; window.__blazorCanvasInterop = { drawLine: (canvas, sX, sY, eX, eY) => { let context = getContext(canvas); context.lineJoin = 'round'; context.lineWidth = 5; context.beginPath(); context.moveTo(eX, eY); context.lineTo(sX, sY); context.closePath(); context.stroke(); }, setContextPropertyValue: (canvas, propertyName, propertyValue) => { let context = getContext(canvas); context(propertyName) = propertyValue; } }; })(window);
我用一个匿名自执行函数创建的闭包范围完成了这个 canvasContextCache
我用它来避免经常得到上下文,不会暴露。
该模块为我们提供了两个函数,第一个是在两个点之间在画布上绘制一条线(我们需要用于涂鸦),第二个更新上下文的属性(我们需要更改颜色 )。
您可能还会注意到我从未打过电话 document.getElementById
,我只是以某种方式“神奇地”得到画布。这可以通过在C#中捕获组件引用并传递该引用来实现。
但这仍然是所有JavaScript,我们在C#中做什么?好吧,我们创建一个C#盘点类
public class Canvas2DContext { private readonly IJSRuntime jsRuntime; private readonly ElementRef canvasRef; public Canvas2DContext(IJSRuntime jsRuntime, ElementRef canvasRef) { this.jsRuntime = jsRuntime; this.canvasRef = canvasRef; } public async Task DrawLine(long startX, long startY, long endX, long endY) { await jsRuntime.InvokeAsync<object>("__blazorCanvasInterop.drawLine", canvasRef, startX, startY, endX, endY); } public async Task SetStrokeStyleAsync(string strokeStyle) { await jsRuntime.InvokeAsync<object>("__blazorCanvasInterop.setContextPropertyValue", canvasRef, "strokeStyle", strokeStyle); } }
这是一个通用类,它采用捕获的引用和JavaScript互操作API,并为我们提供了更好的编程接口。
接线我们的背景
我们现在可以连接上下文并准备在画布上绘制线条:
@page "/" @inject IJSRuntime JsRuntime
通过增加 @ref="@canvas"
我们的 元素我们创建我们需要的引用然后在
OnInitAsync
我们创造的功能 Canvas2DContext
我们将使用。
画在画布上
我们终于准备在画布上绘制一些图形,这意味着我们需要实现这些事件处理程序:
bool isPainting = false; long x; long y; private void StartPaint(UIMouseEventArgs e) { x = e.ClientX; y = e.ClientY; isPainting = true; } private async Task Paint(UIMouseEventArgs e) { if (isPainting) { var eX = e.ClientX; var eY = e.ClientY; await ctx.DrawLine(x, y, eX, eY); x = eX; y = eY; } } private void StopPaint(UIMouseEventArgs e) { isPainting = false; }
不可否认,这些与JavaScript实现没有什么不同,他们所要做的就是从鼠标事件中获取坐标,然后将它们传递给画布上下文盘点器,后者又调用适当的JavaScript函数。
结论
?我们完成了你可以看到它在这里运行,代码在GitHub上。
aaronpowell / blazor-devto-offline
演示如何使用Blazor创建DEV.to的离线页面
此存储库包含如何使用Blazor创建DEV.to脱机页面的示例。
你可以在这里找到它运行https://blazordevtooffline.z23.web.core.windows.net/。
在GitHub上查看
这是Blazor的快速浏览,但更重要的是,我们如何在可能需要我们与许多场景需要的JavaScript进行更多互操作的场景中使用Blazor。
我希望你喜欢它,并准备好解决你自己的Blazor实验
奖金,颜色选择器
在上面的例子中我们没有做过一件事,实现颜色选择器
我想这样做作为通用组件,所以我们可以这样做:
OnClick="@SetStrokeColour" Colours="@colours" />
在一个名为的新文件中 ColourPicker.razor
(文件名很重要,因为这是组件的名称)我们将创建我们的组件:
class="colours"> @foreach (var colour in Colours) { } @code { (Parameter) public Func, Action<UIMouseEventArgs>> OnClick { get; set; } (Parameter) public IEnumerable Colours { get; set; } }
我们的组件将有2个参数,可以从父级,颜色集合和单击按钮时调用的函数进行设置。对于我所做的事件处理程序是这样的,你传入一个返回一个动作的函数,所以它是一个单独的函数,它被绑定到颜色的名称,当 元素已创建。
这意味着我们有这样的用法:
@page "/" @inject IJSRuntime JsRuntime OnClick="@SetStrokeColour" Colours="@colours" /> // snip @code { IEnumerable colours = new() { "#F4908E", "#F2F097", "#88B0DC", "#F7B5D1", "#53C4AF", "#FDE38C" }; // snip private Action SetStrokeColour(string colour) { return async _ => { await ctx.SetStrokeStyleAsync(colour); }; } }
现在,如果您单击顶部的颜色选择器,您将获得不同的颜色笔。
快乐的涂鸦