Blazor组件自做四 : 使用JS隔离封装signature_pad签名组件

2023-11-16

运行截图

演示地址:

响应式:

感谢szimek写的棒棒的signature_pad.js项目, 来源: https://github.com/szimek/signature_pad

正式开始

1. 在文件夹wwwroot/lib,添加signature_pad子文件夹,里面下载库文件(文件文末源码里可复制) signature_pad.umd.js复制到此文件夹. 最终版本参考如下

+signature_pad
  |-signature_pad.umd.js

2. 添加app.js文件

+signature_pad
  |-app.js

代码里 wrapperc.invokeMethodAsync(“signatureResult”, imgBase64) 为签名canvas结果回调到c#

js代码
import '/lib/signature_pad/signature_pad.umd.js';

export function init(wrapperc, element, alertText,) {
    //Code modify from https://github.com/szimek/signature_pad
    var wrapper = element;//document.getElementById("signature-pad");
    var clearButton = wrapper.querySelector("[data-action=clear]");
    var changeColorButton = wrapper.querySelector("[data-action=change-color]");
    var undoButton = wrapper.querySelector("[data-action=undo]");
    var saveBase64Button = wrapper.querySelector("[data-action=save-base64]");
    var savePNGButton = wrapper.querySelector("[data-action=save-png]");
    var saveJPGButton = wrapper.querySelector("[data-action=save-jpg]");
    var saveSVGButton = wrapper.querySelector("[data-action=save-svg]");
    var canvas = wrapper.querySelector("canvas");
    var signaturePad = new SignaturePad(canvas, {
        // It's Necessary to use an opaque color when saving image as JPEG;
        // this option can be omitted if only saving as PNG or SVG
        backgroundColor: 'rgb(255, 255, 255)'
    });

    // Adjust canvas coordinate space taking into account pixel ratio,
    // to make it look crisp on mobile devices.
    // This also causes canvas to be cleared.
    function resizeCanvas() {
        // When zoomed out to less than 100%, for some very strange reason,
        // some browsers report devicePixelRatio as less than 1
        // and only part of the canvas is cleared then.
        var ratio = Math.max(window.devicePixelRatio || 1, 1);

        // This part causes the canvas to be cleared
        canvas.width = canvas.offsetWidth * ratio;
        canvas.height = canvas.offsetHeight * ratio;
        canvas.getContext("2d").scale(ratio, ratio);

        // This library does not listen for canvas changes, so after the canvas is automatically
        // cleared by the browser, SignaturePad#isEmpty might still return false, even though the
        // canvas looks empty, because the internal data of this library wasn't cleared. To make sure
        // that the state of this library is consistent with visual state of the canvas, you
        // have to clear it manually.
        signaturePad.clear();
    }

    // On mobile devices it might make more sense to listen to orientation change,
    // rather than window resize events.
    window.onresize = resizeCanvas;
    resizeCanvas();

    function download(dataURL, filename) {
        if (navigator.userAgent.indexOf("Safari") > -1 && navigator.userAgent.indexOf("Chrome") === -1) {
            window.open(dataURL);
        } else {
            var blob = dataURLToBlob(dataURL);
            var url = window.URL.createObjectURL(blob);

            var a = document.createElement("a");
            a.style = "display: none";
            a.href = url;
            a.download = filename;

            document.body.appendChild(a);
            a.click();

            window.URL.revokeObjectURL(url);
        }
    }

    // One could simply use Canvas#toBlob method instead, but it's just to show
    // that it can be done using result of SignaturePad#toDataURL.
    function dataURLToBlob(dataURL) {
        // Code taken from https://github.com/ebidel/filer.js
        var parts = dataURL.split(';base64,');
        var contentType = parts[0].split(":")[1];
        var raw = window.atob(parts[1]);
        var rawLength = raw.length;
        var uInt8Array = new Uint8Array(rawLength);

        for (var i = 0; i < rawLength; ++i) {
            uInt8Array[i] = raw.charCodeAt(i);
        }

        return new Blob([uInt8Array], { type: contentType });
    }

    if (clearButton) clearButton.addEventListener("click", function (event) {
        signaturePad.clear();
        return wrapperc.invokeMethodAsync("signatureResult", null);
    });

    if (undoButton) undoButton.addEventListener("click", function (event) {
        var data = signaturePad.toData();

        if (data) {
            data.pop(); // remove the last dot or line
            signaturePad.fromData(data);
        }
    });

    if (changeColorButton) changeColorButton.addEventListener("click", function (event) {
        var r = Math.round(Math.random() * 255);
        var g = Math.round(Math.random() * 255);
        var b = Math.round(Math.random() * 255);
        var color = "rgb(" + r + "," + g + "," + b + ")";

        signaturePad.penColor = color;
    });

    if (saveBase64Button) saveBase64Button.addEventListener("click", function (event) {
        if (signaturePad.isEmpty()) {
            alertMessage();
        } else {
            var imgBase64 = signaturePad.toDataURL("image/jpeg");
            //console.log(imgBase64);
            return wrapperc.invokeMethodAsync("signatureResult", imgBase64);
        }
    });

    if (savePNGButton) savePNGButton.addEventListener("click", function (event) {
        if (signaturePad.isEmpty()) {
            alertMessage();
        } else {
            var dataURL = signaturePad.toDataURL();
            download(dataURL, "signature.png");
        }
    });

    if (saveJPGButton) saveJPGButton.addEventListener("click", function (event) {
        if (signaturePad.isEmpty()) {
            alertMessage();
        } else {
            var dataURL = signaturePad.toDataURL("image/jpeg");
            download(dataURL, "signature.jpg");
        }
    });

    if (saveSVGButton) saveSVGButton.addEventListener("click", function (event) {
        if (signaturePad.isEmpty()) {
            alertMessage();
        } else {
            var dataURL = signaturePad.toDataURL('image/svg+xml');
            download(dataURL, "signature.svg");
        }
    });

    function alertMessage() {
        if (alertText) alert(alertText);
        wrapperc.invokeMethodAsync("signatureAlert");
    }
}

3. 打开Components文件夹 , 新建SignaturePad.razor.css文件

css代码
*,
*::before,
*::after {
    box-sizing: border-box;
}

.signature-pad-body {
    display: -webkit-box;
    display: -ms-flexbox;
    display: flex;
    -webkit-box-pack: center;
    -ms-flex-pack: center;
    justify-content: center;
    -webkit-box-align: center;
    -ms-flex-align: center;
    align-items: center;
    height: 400px;
    width: 100%;
    -webkit-user-select: none;
    -moz-user-select: none;
    -ms-user-select: none;
    user-select: none;
    margin: 0;
    padding: 32px 16px;
    font-family: Helvetica, Sans-Serif;
}

.signature-pad {
    position: relative;
    display: -webkit-box;
    display: -ms-flexbox;
    display: flex;
    -webkit-box-orient: vertical;
    -webkit-box-direction: normal;
    -ms-flex-direction: column;
    flex-direction: column;
    font-size: 10px;
    width: 100%;
    height: 100%;
    max-width: 650px;
    max-height: 400px;
    border: 1px solid #e8e8e8;
    background-color: #fff;
    box-shadow: 0 1px 4px rgba(0, 0, 0, 0.27), 0 0 40px rgba(0, 0, 0, 0.08) inset;
    border-radius: 4px;
    padding: 16px;
}

    .signature-pad::before,
    .signature-pad::after {
        position: absolute;
        z-index: -1;
        content: "";
        width: 40%;
        height: 10px;
        bottom: 10px;
        background: transparent;
        box-shadow: 0 8px 12px rgba(0, 0, 0, 0.4);
    }

    .signature-pad::before {
        left: 20px;
        -webkit-transform: skew(-3deg) rotate(-3deg);
        transform: skew(-3deg) rotate(-3deg);
    }

    .signature-pad::after {
        right: 20px;
        -webkit-transform: skew(3deg) rotate(3deg);
        transform: skew(3deg) rotate(3deg);
    }

.signature-pad--body {
    position: relative;
    -webkit-box-flex: 1;
    -ms-flex: 1;
    flex: 1;
    border: 1px solid #f4f4f4;
}

    .signature-pad--body
    canvas {
        position: absolute;
        left: 0;
        top: 0;
        width: 100%;
        height: 100%;
        border-radius: 4px;
        box-shadow: 0 0 5px rgba(0, 0, 0, 0.02) inset;
    }

.signature-pad--footer {
    color: #C3C3C3;
    text-align: center;
    font-size: 1.2em;
    margin-top: 8px;
}

.signature-pad--actions {
    display: -webkit-box;
    display: -ms-flexbox;
    display: flex;
    -webkit-box-pack: justify;
    -ms-flex-pack: justify;
    justify-content: space-between;
    margin-top: 8px;
}

#github img {
    border: 0;
}

@media (max-width: 940px) {
    #github img {
        width: 90px;
        height: 90px;
    }
}


4. 打开Components文件夹 , 新建SignaturePad.razor组件

参考阅读:Blazor组件参数

4.1 组件参数

在 ASP.NET Web Forms 中,可以使用公共属性将参数和数据传递到控件。 这些属性可以使用特性在标记中进行设置,也可以直接在代码中设置。 Razor 组件以类似的方式工作,尽管组件属性还必须使用 [Parameter] 特性进行标记才能被视为组件参数。

以下 Counter 组件定义名为 IncrementAmount 的组件参数,该参数可用于指定每次单击按钮时 Counter 应该递增的数量。

razor

<h1>Counter</h1>

<p>Current count: @currentCount</p>

<button class="btn btn-primary" @onclick="IncrementCount">Click me</button>

@code {
    int currentCount = 0;

    [Parameter]
    public int IncrementAmount { get; set; } = 1;

    void IncrementCount()
    {
        currentCount+=IncrementAmount;
    }
}

若要在 Blazor 中指定组件参数,请像在 ASP.NET Web Forms 中一样使用特性:

razor

<Counter IncrementAmount="10" />

4.2 C#组件参数实例

定义名为 SaveBase64BtnTitle 的组件参数,该参数可用于设置或者获取 [保存为base64]按钮的文本。

定义名为 OnResult 的组件参数,该参数可用于手写签名结果回调。

    /// <summary>
    /// 保存为base64按钮文本/Save as Base64 button title
    /// </summary>
    [Parameter]
    public string SaveBase64BtnTitle { get; set; } = "确定";

    /// <summary>
    /// 手写签名结果回调/SignaturePad result callback method
    /// </summary>
    [Parameter]
    public EventCallback<string> OnResult { get; set; }

4.3 在 Blazor 调用组件页面中指定组件参数

仅获取手写签名结果回调

<SignaturePad OnResult="((e) =>  Result=e)" />

@code{ 
    public string? Result { get; set; }
}

自定义按钮文本

<SignaturePad OnResult="((e) =>  Result=e)" SaveBase64BtnTitle="完成"/>
<SignaturePad OnResult="((e) =>  Result=e)" SaveBase64BtnTitle="OK" ClearBtnTitle="Clear"/>
<SignaturePad OnResult="((e) =>  Result=e)" 
              SignAboveLabel="Sign above" 
              UndoBtnTitle="Undo" 
              SaveBase64BtnTitle="OK" 
              ChangeColorBtnTitle="Change color" 
              ClearBtnTitle="Clear" />

@code{ 
    public string? Result { get; set; }
}

自定义按钮css

<SignaturePad OnResult="((e) =>  Result=e)" BtnCssClass="btn btn-outline-success"/>

@code{ 
    public string? Result { get; set; }
}

4.4 完整代码

razor代码
@implements IAsyncDisposable
@namespace Blazor100.Components
@inject IJSRuntime JS

<div class="signature-pad-body">
    <div @ref="SignaturepadElement" class="signature-pad">
        <div class="signature-pad--body">
            <canvas width="614" style="touch-action: none; user-select: none;" height="242"></canvas>
        </div>
        <div class="signature-pad--footer">
            <div class="description">@SignAboveLabel</div>

            <div class="signature-pad--actions">
                <div>
                    <button type="button" class="@BtnCssClass" data-action="clear">@ClearBtnTitle</button>
                    @if (EnableChangeColorBtn)
                    {
                        <button type="button" class="@BtnCssClass" data-action="change-color">@ChangeColorBtnTitle</button>
                    }
                    <button type="button" class="@BtnCssClass" data-action="undo">@UndoBtnTitle</button>

                </div>
                <div>
                    @if (EnableSaveBase64Btn)
                    {
                        <button type="button" class="@BtnCssClass" data-action="save-base64">@SaveBase64BtnTitle</button>
                    }
                    @if (EnableSavePNGBtn)
                    {
                        <button type="button" class="@BtnCssClass" data-action="save-png">@SavePNGBtnTitle</button>
                    }
                    @if (EnableSaveJPGBtn)
                    {
                        <button type="button" class="@BtnCssClass" data-action="save-jpg">@SaveJPGBtnTitle</button>
                    }
                    @if (EnableSaveSVGBtn)
                    {
                        <button type="button" class="@BtnCssClass" data-action="save-svg">@SaveSVGBtnTitle</button>
                    }
                </div>
            </div>
        </div>
    </div>
</div>

@code {

    /// <summary>
    /// 手写签名结果回调/SignaturePad result callback method
    /// </summary>
    [Parameter]
    public EventCallback<string> OnResult { get; set; }

    /// <summary>
    /// 手写签名警告信息回调/SignaturePad alert callback method
    /// </summary>
    [Parameter]
    public EventCallback<string> OnAlert { get; set; }

    /// <summary>
    /// 获得/设置 错误回调方法
    /// </summary>
    [Parameter]
    public Func<string, Task>? OnError { get; set; }

    /// <summary>
    /// 在框内签名标签文本/Sign above label
    /// </summary>
    [Parameter]
    public string SignAboveLabel { get; set; } = "在框内签名";

    /// <summary>
    /// 清除按钮文本/Clear button title
    /// </summary>
    [Parameter]
    public string ClearBtnTitle { get; set; } = "清除";

    /// <summary>
    /// 请先签名提示文本/'Please provide a signature first' alert text
    /// </summary>
    [Parameter]
    public string SignatureAlertText { get; set; } = "请先签名";

    /// <summary>
    /// 换颜色按钮文本/Change color button title
    /// </summary>
    [Parameter]
    public string ChangeColorBtnTitle { get; set; } = "换颜色";

    /// <summary>
    /// 撤消按钮文本/Undo button title
    /// </summary>
    [Parameter]
    public string UndoBtnTitle { get; set; } = "撤消";

    /// <summary>
    /// 保存为base64按钮文本/Save as Base64 button title
    /// </summary>
    [Parameter]
    public string SaveBase64BtnTitle { get; set; } = "确定";

    /// <summary>
    /// 保存为PNG按钮文本/Save as PNG button title
    /// </summary>
    [Parameter]
    public string SavePNGBtnTitle { get; set; } = "PNG";

    /// <summary>
    /// 保存为JPG按钮文本/Save as JPG button title
    /// </summary>
    [Parameter]
    public string SaveJPGBtnTitle { get; set; } = "JPG";

    /// <summary>
    /// 保存为SVG按钮文本/Save as SVG button title
    /// </summary>
    [Parameter]
    public string SaveSVGBtnTitle { get; set; } = "SVG";

    /// <summary>
    /// 启用换颜色按钮/Enable change color button
    /// </summary>
    [Parameter]
    public bool EnableChangeColorBtn { get; set; } = true;

    /// <summary>
    /// 启用JS错误弹窗/Enable Alert from JS
    /// </summary>
    [Parameter]
    public bool EnableAlertJS { get; set; } = true;

    /// <summary>
    /// 启用保存为base64按钮/Enable save as Base64 button
    /// </summary>
    [Parameter]
    public bool EnableSaveBase64Btn { get; set; } = true;

    /// <summary>
    /// 启用保存为PNG按钮文本/Enable save as PNG button
    /// </summary>
    [Parameter]
    public bool EnableSavePNGBtn { get; set; } = false;

    /// <summary>
    /// 启用保存为JPG按钮文本/Enable save as JPG button
    /// </summary>
    [Parameter]
    public bool EnableSaveJPGBtn { get; set; } = false;

    /// <summary>
    /// 启用保存为SVG按钮文本/Enable save as SVG button
    /// </summary>
    [Parameter]
    public bool EnableSaveSVGBtn { get; set; } = false;

    /// <summary>
    /// 按钮CSS式样/Button css style
    /// </summary>
    [Parameter]
    public string BtnCssClass { get; set; } = "btn btn-light";

    private IJSObjectReference? module;

    /// <summary>
    ///
    /// </summary>
    protected ElementReference SignaturepadElement { get; set; }

    // To prevent making JavaScript interop calls during prerendering
    protected override async Task OnAfterRenderAsync(bool firstRender)
    {
        if (!firstRender) return;
        try
        {
            module = await JS.InvokeAsync<IJSObjectReference>("import", "./lib/signature_pad/app.js");
            await module.InvokeVoidAsync("init", DotNetObjectReference.Create(this), SignaturepadElement, EnableAlertJS ? SignatureAlertText : null);
        }
        catch (Exception e)
        {
            if (OnError != null) await OnError.Invoke(e.Message);
        }
    }

    [JSInvokable("signatureResult")]
    public async Task SignatureResult(string val)
    {
        if (OnResult.HasDelegate) await OnResult.InvokeAsync(val);
    }

    [JSInvokable("signatureAlert")]
    public async Task SignatureAlert()
    {
        if (OnResult.HasDelegate) await OnAlert.InvokeAsync(SignatureAlertText);
    }


    async ValueTask IAsyncDisposable.DisposeAsync()
    {
        if (module is not null)
        {
            //await module.InvokeVoidAsync("destroy",null);
            await module.DisposeAsync();
        }
    }
}


5. Pages文件夹添加SignaturePadPage.razor文件,用于演示组件调用.

SignaturePadPage.razor代码
@page "/signaturepad"

<h3>SignaturePad 签名</h3>

<SignaturePad OnResult="((e) =>  Result=e)" /> 

@code{

    /// <summary>
    /// 签名Base64
    /// </summary>
    public string? Result { get; set; } 
}


6. _Imports.razor加入一行引用组件的命名空间.

@using Blazor100.Components

7. 首页引用组件演示页 <SignaturePadPage />或者Shared/NavMenu.razor添加导航

        <div class="nav-item px-3">
            <NavLink class="nav-link" href="signaturepad">
                <span class="oi oi-plus" aria-hidden="true"></span> 手写签名2
            </NavLink>
        </div>

8. F5运行程序

9. Tips: 复杂签名会导致传输数据量大ssr会出现断流显示reload错误,启用以下配置解决这个问题.

        builder.Services.AddServerSideBlazor(a =>
        {
            //异步调用JavaScript函数的最大等待时间
            a.JSInteropDefaultCallTimeout = TimeSpan.FromMinutes(2);
        }).AddHubOptions(o =>
        {
            //单个传入集线器消息的最大大小。默认 32 KB
            o.MaximumReceiveMessageSize = null;
            //可为客户端上载流缓冲的最大项数。 如果达到此限制,则会阻止处理调用,直到服务器处理流项。
            o.StreamBufferCapacity = 20;
        });

至此,使用JS隔离封装signature_pad签名组件大功告成! Happy coding!

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Blazor组件自做四 : 使用JS隔离封装signature_pad签名组件 的相关文章

  • 该组件没有由 uri 标识的资源

    我想创建一个通用数据网格以在我的所有视图 用户控件上使用 这是我的结构 Class Library called Core Class called ViewBase public class ViewBase UserControl pu
  • Sitecore - 隐藏功能区中的按钮

    我为特定内容项创建了上下文功能区 我有两个按钮 可以将项目 升级 或 降级 到某一类别 该部分只能有一个 是否可以根据某种隐藏代码中的内容状态隐藏其中一个按钮 我了解如何链接到 Click 事件 但我想知道是否有某种加载事件可供自定义功能区
  • 如何在 VS2017/2015 中打开 .xproj 文件

    我有一个带有扩展名的 NET core 项目 xproj 当我在VS 2017中打开项目时 项目文件 xproj migrated to csproj 如何打开 xproj 文件 Visual Studio 2017 2015 我需要安装任
  • 调整图像的亮度、对比度和伽玛值

    在 NET 中调整图像的亮度 对比度和伽玛值的简单方法是什么 c and gdi have a simple way to control the colors that are drawn It s basically a ColorMa
  • “你好世界!!”在 .NET 4 中生成 3500 个页面错误

    我正在运行 Windows Vista 和 Visual Studio 2010 使用 NET 4 2 GB RAM 和大约 800 MB 可用空间 我创建了一个 Windows 窗体应用程序 但没有向其中添加任何代码 只需在发布模式下编译
  • 如何等待远程 .NET 调试器连接

    今天我遇到了一个问题 我需要远程调试程序 该程序是从另一个系统启动的 所以我真的没有机会在命令行上与它交互 不过我可以很容易地改变它的来源 我需要做的是让程序正常启动 然后等待我用调试器附加到它 我想不出一个让我快乐的方法 我确实发现了这个
  • 从经典 ASP 调用 .Net C# DLL 方法

    我正在开发一个经典的 asp 项目 该项目需要将字符串发送到 DLL DLL 会将其序列化并发送到 Zebra 热敏打印机 我已经构建了我的 DLL 并使用它注册了regasm其次是 代码库这使得 IIS 能够识别它 虽然我可以设置我的对象
  • C# 中的 IPC 机制 - 用法和最佳实践

    不久前我在 Win32 代码中使用了 IPC 临界区 事件和信号量 NET环境下场景如何 是否有任何教程解释所有可用选项以及何时使用以及为什么 微软最近在IPC方面的东西是Windows 通信基础 http en wikipedia org
  • 如何在C#背后的代码中动态创建数据模板并绑定TreeView分层数据

    我有一个场景 其中树视图动态更改其数据模板和数据绑定定义 我在 XAML 中创建了一个树视图 如下所示
  • 如何拦截 Boo 中的方法调用?

    红宝石有method missing Python有getattr Boo 是否提供了一些可以用来拦截方法调用的东西 是的 布有IQuackFu http docs codehaus org pages viewpage action pa
  • 当操作系统显示语言为非英语时获取本地时区标识符

    奇怪的是 TimeZone CurrentTimeZone StandardName根据计算机显示语言返回本地化名称 我想要一个可以提供给的程序化标识符TimeZoneInfo在下面的代码中 TimeZoneInfo timeZoneInf
  • 比较已编译的 .NET 程序集?

    有没有什么好的程序可以与编译 NET 程序集进行比较 例如 我有 HelloWorld dll 1 0 0 0 和 HelloWorld dll 2 0 0 0 我想比较差异 我该怎么做 我知道我可以使用 NET Reflector 并使用
  • 由于索引无效,无法加载计数器名称数据 -Exception

    我使用 C 和 WPF 操作系统是 windows 7 Professional 和 Visual Studio 2012 SQL Server 2012 我在wpf中使用了Devexpress Grid 我想使用 ADO Net 服务器模
  • 在 JsonConverter 中递归调用 JsonSerializer

    我正在写一个JsonConverter要执行一些我需要在读 写时完成的转换任务 特别是 我采用现有的序列化行为 并在写入 读取时添加一些附加属性 在 的里面JsonConverter 我想利用通过的JsonSerializer实例来执行大部
  • Java 中等效的并行扩展

    我在 Net 开发中使用并行扩展有一些经验 但我正在考虑在 Java 中做一些工作 这些工作将受益于易于使用的并行库 JVM 是否提供任何与并行扩展类似的工具 您应该熟悉java util concurrent http java sun
  • 为什么两个不同的 Base64 字符串的转换会返回相等的字节数组?

    我想知道为什么从 base64 字符串转换会为不同的字符串返回相同的字节数组 const string s1 dg const string s2 dq byte a1 Convert FromBase64String s1 byte a2
  • .NET 中是否有内置函数可以对密码进行哈希处理?

    我看到这个问题加密 散列数据库中的纯文本密码 https stackoverflow com questions 287517 encrypting hashing plain text passwords in database 我知道我
  • 垃圾收集器是否在单独的进程中运行?

    垃圾收集器是否在单独的进程中启动 例如 如果我们尝试测量某段代码所花费的进程时间 并且在此期间垃圾收集器开始收集 它会在新进程上启动还是在同一进程中启动 它的工作原理如下吗 Code Process 1 gt Garbage Collect
  • C# 模拟VolumeMute按下

    我得到以下代码来模拟音量静音按键 DllImport coredll dll SetLastError true static extern void keybd event byte bVk byte bScan int dwFlags
  • 使用.NET技术录制屏幕视频[关闭]

    Closed 这个问题正在寻求书籍 工具 软件库等的推荐 不满足堆栈溢出指南 help closed questions 目前不接受答案 有没有一种方法可以使用 NET 技术来录制屏幕 无论是桌面还是窗口 我的目标是免费的 我喜欢小型 低

随机推荐

  • 搭建个人静态blog

    前言 也是无意间看到一个写个人博客的 看着非常的好看 于是乎一个牛逼而又der想法就产生了 我也要搞一个人的blog 就显摆一下 就是玩 于是这个blog就产生了 写完之后的也是非常的激动 赶紧发给朋友 显摆显摆 后来朋友也都很惊讶 确实还
  • 机器学习-k-近邻算法

    k 近邻算法 一 k 近邻算法概述 1 1 使用python导入数据 1 2 从文本文件中解析数据 二 使用k 近邻算法改进约会网站的配对效果 2 1 准备数据 2 2 数据预处理 2 3 分析数据 2 4 测试算法 2 5使用算法 三 手
  • [docker]笔记-基础配置

    1 docker启动和设置开机启动 root localhost systemctl start docker root localhost systemctl enable docker 2 更换docker镜像网站 默认docker镜像
  • SpringSecurity学习笔记一

    SpringSecurity学习笔记 一 Java配置 Web安全 创建Security过滤器 通过springSecurityFilterChain负责所有安全过滤请求 基本例子 EnableWebSecurity public clas
  • Android 中SharedPreferences的详解

    博主前些天发现了一个巨牛的人工智能学习网站 通俗易懂 风趣幽默 忍不住也分享一下给大家 点击跳转到网站 一 SharedPreferences 首选项 介绍 存储软件的配置信息 存储的信息 很小 简单的数据 比如 自动登录 记住密码 小说a
  • 入门级详细USB移植教程——致正在为USB烦恼的朋友

    同上一篇MPU6050一样 我还是写一篇关于USB的帖子 在圈圈等玩USB的大神面前 我掌握的USB知识实在是九牛一毛 所以这篇帖子加上了入门级的修饰语 写这篇帖子主要是为了那些想快速开发USB的人 至于想深入了解USB协议 可以先学完我这
  • 游戏开发unity编辑器扩展知识系列:AssetDatabase.SaveAssets

    插眼 总结 在Editor运行c 脚本时 可以修改资源 这时如果想要保存修改 可以调用AssetDatabase SaveAssets 参考 官方文档 https docs unity3d com ScriptReference Asset
  • 记一次ES线上异常

    记一次ES线上异常解决过程 周六线上es报警es not green 由于没有带笔记本回家并且考虑到集群容量本身就很紧张以及最近的读写压力确实很大 并没有多余的机器可以加入集群 觉得应该不会是什么大问题 就没有太多在意 周末去上班打开电脑一
  • 如何调用百度接口来实现全国的撒点效果(在这里把百度接口的文档荡到本地了)

  • LogisticRegression用户流失预测模型初探【推荐】

    什么是逻辑回归 Logistic回归与多重线性回归实际上有很多相同之处 最大的区别就在于它们的因变量不同 其他的基本都差不多 正是因为如此 这两种回归可以归于同一个家族 即广义线性模型 generalizedlinear model 这一家
  • 「c++小学期」实验题目及代码

    面向对象编程的C 和平时做题用的C 还是有差距的 实验的题目都是小题目 就都做一下吧 实验一 简单C 程序设计 1 猜价格游戏 编写C 程序完成以下功能 1 假定有一件商品 程序用随机数指定该商品的价格 1 1000的整数 2 提示用户猜价
  • 【AI with ML】第 8 章 :使用 TensorFlow 创建文本

    大家好 我是Sonhhxg 柒 希望你看完之后 能对你有所帮助 不足请指正 共同学习交流 个人主页 Sonhhxg 柒的博客 CSDN博客 欢迎各位 点赞 收藏 留言 系列专栏 机器学习 ML 自然语言处理 NLP 深度学习 DL fore
  • styled-components设置组件属性

    问题 最近在试着用react做一个音乐播放器 在这之前其实并不了解styled components 但由于使用css in js并且想实现hover效果 百度各种解决方案后发现了styled components这个好东西 如果你看到了这
  • RGMII接口(KSZ9031)

    概述 RGMII的时序是时钟双沿采样 在默认的RGMII时序中 时钟 RXC TXC 边沿与数据边沿 TXD RXD TX CTL RX CTL 的对齐 因此 FPGA想要正确收发数据 需要对TXC或RXC进行适当的延迟 由于最高时钟为12
  • 二手房交易差额款需要一次交清?

    在签订购房合同的时候 房东要求添加条款 在房产过户当日收取差额款 差额款应该一次性给他 还是可以按比例付 拿到房产证后付清 他给我写收条的时候 我应该注意什么 找法网小编为您详细介绍 网友咨询 我通过本地的老牌中介买房的 在签订购房合同的时
  • 时间序列数据特征提取TsFresh

    文章目录 1 源码和数据地址 2 TsFresh安装 3 代码部分说明 3 1 数据下载 3 2 从文件读取数据 4 特征拓展 4 1 默认参数 4 2 ComprehensiveFCParameters参数 4 3 EfficientFC
  • 电子工程师的自我修养 - OD输出

    开漏输出 Open Drain Output OD门 漏极开路 Open Drain 电路特点 利用外部电路的驱动能力 减少IC内部的驱动 可以将多个开漏输出的pin连接到一条线上 通过一个上拉电阻 在不增加任何器件的情况下 形成 线与 关
  • 使用myisamchK 命令修复数据

    使用myisamchk 命令修复表 myisam使用程序可以用来获得有关你的数据库表的统计信息 检查 修复 优化他们 命令格式 myisamchk option tables frm 常用的检查选项 information i 打印所检察标
  • 韦东山 IMX6ULL和正点原子_「正点原子NANO STM32开发板资料连载」第三章 MDK5 软件入门1...

    1 实验平台 ALIENTEK NANO STM32F411 V1开发板 2 摘自 正点原子STM32F4 开发指南 HAL 库版 关注官方微信号公众号 获取更多资料 正点原子 第三章 MDK5 软件入门 本章将向大家介绍 MDK5 软件和
  • Blazor组件自做四 : 使用JS隔离封装signature_pad签名组件

    运行截图 演示地址 响应式 感谢szimek写的棒棒的signature pad js项目 来源 https github com szimek signature pad 正式开始 1 在文件夹wwwroot lib 添加signatur