我认为单独使用 C# 实现这一点并不容易,因为解决该问题的最佳方法是将 HTML 数据转换为画布并将其导出为图像,这是一个艰难的过程,但是有一些库在 JS 中可用。
怎么做:
我将使用这个库,因为它似乎是最简单的:html2canvas
这是它的 JS 文件的链接:html2canvas.js
下载它并将其放在您的 wwwroot 文件夹中,然后通过在正文标记的末尾添加以下内容将其包含在 _host.cshtml 中:
<script src="html2canvas.js"></script>
然后添加一个从 C# 调用的 JS 函数,这样我们就可以在 _host.cshtml 中的前面代码之后添加这个用 C# 编写的偶数处理程序:
<script>
window.takeScreenshot = async function(id) {
var img = "";
await html2canvas(document.querySelector("#" + id)).then(canvas => img = canvas.toDataURL("image/png"));
var d = document.createElement("a");
d.href = img;
d.download = "image.png";
d.click();
return img;
}
</script>
这将自动从元素中截取并下载它,同时返回它的 URL。注意该组件必须在带有id的div标签内,否则不能单独选择,例如父级中的好孩子:
Parent.razor
<div id="child"></div>
<Child />
</div>
要使用此功能,请使用JsInterop 类。简单地,通过在文件顶部添加它来将它注入(基本上包含)到您需要此功能的剃须刀组件中:
@inject IJSRuntime JS
接下来,一个做所有事情的函数:
@inject IJSRuntime JS
@code {
public async System.Threading.Tasks.Task<string> TakeImage(string id)
{
return await JS.InvokeAsync<string>("takeScreenshot", id);
}
}
此函数将返回从 id 参数指定的元素中获取的图像的数据 URL。
使用按钮拍摄图像的示例用法:
@page "/screenshot"
@inject IJSRuntime JS
@code {
string image_url = "";
string child_id = "child";
public async System.Threading.Tasks.Task<string> TakeImage(string id)
{
return await JS.InvokeAsync<string>("takeScreenshot", id);
}
public async System.Threading.Tasks.Task ButtonHandler()
{
image_url = await TakeImage(child_id);
}
}
<button @onclick="ButtonHandler">Take image</button>
<h3>Actual component:</h3>
<div id=@child_id>
<ChildComponent />
</div>
<h3>Image:</h3>
<img src=@image_url />
<br />
<br />
<br />
<p>URL: @image_url</p>
按下按钮将下载图像,显示它,显示原始 URL,并将 URL 保存到变量 image_url。
您可以通过将@using System.Threading.Tasks 添加到_Imports.razor 文件来将System.Threading.Tasks.Task 缩短为Task。
您可以通过删除 JS 函数中的这 4 行来删除自动下载功能:
var d = document.createElement("a");
d.href = img;
d.download = "image.png";
d.click();
如果您想自动拍摄整个页面的图像并在没有任何用户交互的情况下下载:
修改JS函数,将查询选择器设置为body,去掉id参数:
<script>
window.takeScreenshot = async function() {
var img = "";
await html2canvas(document.querySelector("body")).then(canvas => img = canvas.toDataURL("image/png"));
var d = document.createElement("a");
d.href = img;
d.download = "image.png";
d.click();
return img;
}
</script
设置函数在文档加载时运行:
@inject IJSRuntime JS
@page "/component"
@code {
string image_url = "";
public async System.Threading.Tasks.Task<string> TakeImage()
{
return await JS.InvokeAsync<string>("takeScreenshot");
}
protected override async System.Threading.Tasks.Task OnAfterRenderAsync(bool firstRender)
{
if(firstRender) //Ensure this is the page load, not any page rerender
{
image_url = await TakeImage();
}
}
}
自动下载图片的特殊网址:
生成一个 URL,在加载时将下载图像作为前一部分,但仅在加载该特殊 URL 时,而不是正常页面 URL。
为此,我将使用查询字符串,因此特殊 URL 将如下所示:http://localhost:5001/page?img=true
为此,我们需要使用NavigationManager 获取URI,它可以像IJSRuntime 一样注入。对于解析 URI,我们可以使用 QueryHelpers 类。
最终代码将如下所示:
@inject IJSRuntime JS
@inject NavigationManager Nav
@page "/component"
@code {
string image_url = "";
public async System.Threading.Tasks.Task<string> TakeImage()
{
return await JS.InvokeAsync<string>("takeScreenshot");
}
protected override async System.Threading.Tasks.Task OnAfterRenderAsync(bool firstRender)
{
if(firstRender) //Ensure this is the page load, not any page rerender
{
var uri = Nav.ToAbsoluteUri(Nav.Uri);
if (Microsoft.AspNetCore.WebUtilities.QueryHelpers.ParseQuery(uri.Query).TryGetValue("img", out var isImg))
{
if (System.Convert.ToBoolean(isImg.ToString()))
{
image_url = await TakeImage();
}
}
}
}
}
现在您可以将?img=true 添加到组件的 URL 中,您将获得它的屏幕截图。
注意,如果 div 的 body/parent 有背景,并且您希望它出现在图像中,则需要在包含子组件的 div 的 CSS 规则中添加 background: inherit;。