Blazor组件自做二 : 使用JS隔离制作手写签名组件

本文相关参考链接

  1. JavaScript 模块中的 JavaScript 隔离
  2. Viewer.js工程
  3. Blazor组件自做一 : 使用JS隔离封装viewerjs库

Blazor JS 隔离优势

导入的 JS 不再污染全局命名空间。

库和组件的使用者不需要导入相关的 JS。即不需要再在ssr的 Pages/_Host.cshtml 或 Pages/_Layout.cshtml ,wasm的 wwwroot/index.html 里写

第一遍载入静态资产请求包含值为 no-cache 或 max-age(值为零 (0))的 标头。真正页面组件使用才载入真实大小文件。

继续Day2正文,以下基础步骤再走一遍,Day3之后不再赘述.

1. 打开VS2020, 新建工程面板, 项目模板搜索 blazor , 选择Blazor Server应用. (wasm也可以,但是不好调试,先从简单的SSR入手)

2. 工程名称改为Blazor100,下一步,默认设置, 保存.



3. 右键点击wwwroot文件夹,添加lib文件夹,添加handwritten子文件夹,里面添加handwritten.js文件, 添加handwritten.css文件 . 最终版本参考如下



4. 编写js文件. 主要是使用Canvas画线,附加功能可生成今日日期等等各位可以自行修改.
handwritten.js代码
export function init(wrapper, options) {
console.log('start handwritten'); /**
* 格式化日期.
*/
Date.prototype.format = function (fmt) {
var o = {
"M+": this.getMonth() + 1, //月份
"d+": this.getDate(), //日
"h+": this.getHours(), //小时
"m+": this.getMinutes(), //分
"s+": this.getSeconds(), //秒
"q+": Math.floor((this.getMonth() + 3) / 3), //季度
"S": this.getMilliseconds() //毫秒
};
if (/(y+)/.test(fmt)) {
fmt = fmt.replace(RegExp.$1, (this.getFullYear() + "").substr(4 - RegExp.$1.length));
}
for (var k in o) {
if (new RegExp("(" + k + ")").test(fmt)) {
fmt = fmt.replace(RegExp.$1, (RegExp.$1.length == 1) ?
(o[k]) : (("00" + o[k]).substr(("" + o[k]).length)));
}
}
return fmt;
} /**
* 获取URL参数
*/
function getQueryString(name) {
var reg = new RegExp("(^|&)" + name + "=([^&]*)(&|$)", "i");
var r = window.location.search.substr(1).match(reg);
if (r != null) return unescape(r[2]); return null;
}
/**
* 是否数字
*/
function isNumeric(n) {
return !isNaN(parseFloat(n)) && isFinite(n);
} function myRedirect(nextw) {
event.returnValue = false;//加这句
this.location.href = nextw;
}
//当页面高度超过设备可见高度时,阻止掉touchmove事件。
document.body.addEventListener('touchmove', function (e) {
e.preventDefault(); //阻止默认的处理方式(阻止下拉滑动的效果)
}, { passive: false }); //passive 参数不能省略,用来兼容ios和android new lineCanvas({
el: document.getElementById("canvas"), //绘制canvas的父级div
clearEl: document.getElementById("clearCanvas"), //清除按钮
saveEl: document.getElementById("saveCanvas"), //保存按钮
// linewidth:1,//线条粗细,选填
// color:"black",//线条颜色,选填
// background:"#ffffff"//线条背景,选填
}); function lineCanvas(obj) {
this.linewidth = 1;
this.color = "#000000";
this.background = "#ffffff";
for (var i in obj) {
this[i] = obj[i];
};
this.canvas = document.createElement("canvas");
this.el.appendChild(this.canvas);
this.cxt = this.canvas.getContext("2d");
this.canvas.width = this.el.clientWidth;
this.canvas.height = this.el.clientHeight; this.cxt.fillStyle = this.background;
this.cxt.fillRect(0, 0, this.canvas.width, this.canvas.height); //this.cxt.fillStyle = "red";
//this.cxt.font = "16px verdana";
//this.cxt.textAlign = "left"; ////fillText("要添加的文字",x0坐标,y0坐标)
//var orderedtime = new Date().getTime();
//orderedtime = (new Date(orderedtime)).format("yyyy-MM-dd hh:mm");
//this.cxt.fillText(orderedtime, 30, 30); this.cxt.fillStyle = this.background;
this.cxt.strokeStyle = this.color;
this.cxt.lineWidth = this.linewidth;
this.cxt.lineCap = "round";
//开始绘制
this.canvas.addEventListener("touchstart", function (e) {
this.cxt.beginPath();
this.cxt.moveTo(e.changedTouches[0].pageX, e.changedTouches[0].pageY);
}.bind(this), false);
//绘制中
this.canvas.addEventListener("touchmove", function (e) {
this.cxt.lineTo(e.changedTouches[0].pageX, e.changedTouches[0].pageY);
this.cxt.stroke();
}.bind(this), false);
//结束绘制
this.canvas.addEventListener("touchend", function () {
this.cxt.closePath();
}.bind(this), false);
//清除画布
this.clearEl.addEventListener("click", function () {
this.cxt.clearRect(0, 0, this.canvas.width, this.canvas.height);
}.bind(this), false);
//保存图片,直接转base64
this.saveEl.addEventListener("click", function () {
var imgBase64 = this.canvas.toDataURL();
console.log(imgBase64);
return wrapper.invokeMethodAsync("invokeFromJS", imgBase64);
}.bind(this), false);
//添加日期时间
function adddatetime() {
this.cxt.fillStyle = "red";
this.cxt.font = "12px '微软雅黑'";
this.cxt.textAlign = "left";
//fillText("要添加的文字",x0坐标,y0坐标)
var orderedtime = new Date().getTime();
orderedtime = (new Date(orderedtime)).format("yyyy-MM-dd hh:mm");
this.cxt.strokeText(orderedtime, 50, 100);
}
}; } export function destroy(options) {
}
5. 编写 handwritten.css 文件. (细心的朋友应该发现,跟Day1不一样,这个css放在lib里面,留着大家思考 :-> )
handwritten.css代码
#canvas {
width: 99%;
/*max-width: 375px;*/
height: 300px;
position: relative;
overflow: hidden;
overflow: -Scroll;
} #canvas canvas {
display: block;
} #clearCanvas0 {
width: calc(50% - 5px);
height: 40px;
line-height: 40px;
text-align: center;
position: absolute;
top: 300px;
left: 5px;
border: 1px solid #DEDEDE;
z-index: 1;
} #saveCanvas0 {
width: calc(50% - 5px);
height: 40px;
line-height: 40px;
text-align: center;
position: absolute;
top: 300px;
right: 5px;
border: 1px solid #DEDEDE;
z-index: 1;
}
6. 点开或者新建Components文件夹 , 新建Handwritten.razor组件,签名会直接转化为Base64编码的string,同学们自己保存到数据库或者当作变量传递就行

组件的命名空间统一使用Blazor100.Components,在razor文件和razor.cs都使用统一命名空间,这样不会受到文件夹嵌套各种影响.

Handwritten.razor代码
@implements IAsyncDisposable
@namespace Blazor100.Components
@inject IJSRuntime JS <link href="lib/handwritten/handwritten.css" rel="stylesheet" /> <div class="modal alert-popup" tabindex="-1" style="display:block" role="dialog">
<div class="modal-dialog-w100">
<div class="modal-content">
<!-- Edit form for the current item -->
<div id="canvas" style="height: 300px;">
</div>
<div>
<button class="btn btn-secondary p-2 m-1 w-25" id="clearCanvas">清除</button>
<button class="btn btn-primary p-2 m-1 w-25" id="saveCanvas">保存</button>
</div>
</div>
</div>
</div>
@Result @code {
/// <summary>
/// Handwritten 手写签名
/// </summary>
[Parameter]
public EventCallback<string> HandwrittenBase64 { get; set; } /// <summary>
/// 关闭扫码框回调方法
/// </summary>
[Parameter]
public EventCallback Close { get; set; } /// <summary>
/// 签名结果,签名会直接转化为Base64编码的string,保存到数据库或者当作变量传递都可以
/// </summary>
[Parameter]
public string? Result { get; set; } private IJSObjectReference? module; // To prevent making JavaScript interop calls during prerendering
protected override async Task OnAfterRenderAsync(bool firstRender)
{
if (!firstRender) return;
module = await JS.InvokeAsync<IJSObjectReference>("import", "./lib/handwritten/handwritten.js");
await module.InvokeVoidAsync("init", DotNetObjectReference.Create(this), null);
} [JSInvokable("invokeFromJS")]
public async Task ChangeValue(string val)
{
Result = val;
StateHasChanged();
await HandwrittenBase64.InvokeAsync(val);
//return Task.CompletedTask;
} async ValueTask IAsyncDisposable.DisposeAsync()
{
if (module is not null)
{
//await module.InvokeVoidAsync("destroy",null);
await module.DisposeAsync();
}
}
}
7. Pages文件添加HandwrittenPage.razor文件,用于演示组件调用.
HandwrittenPage.razor代码
@page "/handwritten"

<h3>Handwritten 手写签名</h3>
<h6>注意:只支持移动设备签名,桌面版浏览器测试请打开F12模拟为移动设备.</h6> <button class="btn btn-primary"
type="button"
@onclick="(() => ShowHandwritten = !ShowHandwritten)">
[签名]
</button>
<textarea type="text" class="form-control" style="min-width: 100px;" rows="10"
@bind="DrawBase64"
placeholder="Base64" />
@if (ShowHandwritten)
{ <Handwritten HandwrittenBase64="(e => { DrawBase64=e; ShowHandwritten = !ShowHandwritten; })"
Close="(()=>ShowHandwritten=!ShowHandwritten)" /> } @code{ /// <summary>
/// 显示签名界面
/// </summary>
bool ShowHandwritten { get; set; } = false; /// <summary>
/// 签名Base64
/// </summary>
public string? DrawBase64 { get; set; } }
8. _Imports.razor加入一行引用组件的命名空间,已经有这行就不需要再重复写了.
@using Blazor100.Components

9. 首页引用组件演示页 <HandwrittenPage />

10. F5运行程序,将会自动打开浏览器调试

签名结果会直接转化为Base64编码的string,保存到数据库或者当作变量传递都可以

至此,使用JS隔离制作手写签名组件大功告成! Happy coding!

Blazor组件自做系列

Blazor组件自做一 : 使用JS隔离封装viewerjs库

Blazor组件自做二 : 使用JS隔离制作手写签名组件

Blazor组件自做三 : 使用JS隔离封装ZXing扫码

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

Blazor组件自做五: 使用JS隔离封装Google地图<03-24>

Blazor组件自做六: 使用JS隔离封装Baidu地图<03-25>

Blazor组件自做七: 使用JS隔离制作定位/持续定位组件<03-26>

Blazor组件自做八: 使用JS隔离封装屏幕键盘kioskboard.js组件<03-27>

项目源码 Github | Gitee

Blazor组件自做二 : 使用JS隔离制作手写签名组件的更多相关文章

  1. Blazor组件自做八 : 使用JS隔离封装屏幕键盘kioskboard.js组件

    1. 运行截图 演示地址 2. 在文件夹wwwroot/lib,添加kioskboard子文件夹,添加kioskboards.js文件 2.1 常规操作,懒加载js库, export function ...

  2. Blazor组件自做一 : 使用JS隔离封装viewerjs库

    Viewer.js库是一个实用的js库,用于图片浏览,放大缩小翻转幻灯片播放等实用操作 本文相关参考链接 JavaScript 模块中的 JavaScript 隔离 Viewer.js工程 Blazo ...

  3. Blazor组件自做三 : 使用JS隔离封装ZXing扫码

    Blazor组件自做三 : 使用JS隔离封装ZXing扫码 本文基础步骤参考前两篇文章 Blazor组件自做一 : 使用JS隔离封装viewerjs库 Blazor组件自做二 : 使用JS隔离制作手写 ...

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

    运行截图 演示地址 响应式演示 感谢szimek写的棒棒的signature_pad.js项目, 来源: https://github.com/szimek/signature_pad 正式开始 1. ...

  5. Blazor组件自做五 : 使用JS隔离封装Google地图

    Blazor组件自做五: 使用JS隔离封装Google地图 运行截图 演示地址 正式开始 1. 谷歌地图API 谷歌开发文档 开始学习 Maps JavaScript API 的最简单方法是查看一个简 ...

  6. Blazor组件自做六 : 使用JS隔离封装Baidu地图

    1. 运行截图 演示地址 2. 在文件夹wwwroot/lib,添加baidu子文件夹,添加baidumap.js文件 2.1 跟上一篇类似,用代码方式异步加载API,脚本生成新的 body > ...

  7. Blazor组件自做七 : 使用JS隔离制作定位/持续定位组件

    1. 运行截图 演示地址 2. 在文件夹wwwroot/lib,添加geolocation子文件夹,添加geolocation.js文件 本组件主要是调用浏览器两个API实现基于浏览器的定位功能,现代 ...

  8. 微信小程序:手写日历组件

    一.前言 最近公司要做一个酒店入住的小程序,不可避免的一定会使用到日历,而小程序没有内置的日历组件.在网上看了一下也没有非常适合需求的日历,于是自己写了一个. 二.代码 1. 原理分析 写一个日历只需 ...

  9. 利用html 5 websocket做个山寨版web聊天室(手写C#服务器)

    在之前的博客中提到过看到html5 的websocket后很感兴趣,终于可以摆脱长轮询(websocket之前的实现方式可以看看Developer Works上的一篇文章,有简单提到,同时也说了web ...

随机推荐

  1. redis php使用实例

    redis的操作很多的,以前看到一个比较全的博客,但是现在找不到了.查个东西搜半天,下面整理一下php处理redis的例子,个人觉得常用一些例子.下面的例子都是基于php-redis这个扩展的. 1, ...

  2. Kubernetes系列(一)Pod

    作者: LemonNan 原文地址: https://juejin.im/post/6862733649272537102 简单介绍 Pod 在 kubernetes 中是一个非常重要的基本概念, 别 ...

  3. Flask Web开发读书笔记

    开篇:目前想自学Flask Web开发--基于Python,找了几本书准备啃啃,同时也会分享读书笔记.希望和大家一起进步. Flask是小型框架,可以算是微框架,但是他的功能还是比较多 Flask有三 ...

  4. vmware下的manjaro挂载共享文件夹

    开始时在archwiki上看到的是以下命令 mkdir <shared folders root directory> vmware-hgfsclient vmhgfs-fuse -o a ...

  5. 6月6日 python学习总结 jQuery (三)

    1. 常用事件 1. hover #鼠标悬停监听 2. keydown和keyup #键盘按键 按下/抬起 3. change #监听值的改变 全部输入完失去焦点后 4. focus和blur # 获 ...

  6. 后门及持久化访问2----进程注入之AppCertDlls 注册表项

    代码及原理介绍 如果有进程使用了CreateProcess.CreateProcessAsUser.CreateProcessWithLoginW.CreateProcessWithTokenW或Wi ...

  7. python练习册 每天一个小程序 第0011题

    1 # -*-coding:utf-8-*- 2 3 4 def test(content): 5 flag = 0 6 with open('filtered_words.txt') as fp: ...

  8. APIO2015 八邻旁之桥/巴邻旁之桥

    题目描述: bz luogu 题解: 贪心+权值线段树. $K=1$的时候,答案为$\sum |x-l| + |x-r|$,所以所有端点排序后取中位数即可. $K=2$的时候,一定是左边的一些走左边的 ...

  9. bzoj3144 [HNOI2013]切糕(最小割)

    bzoj3144 [HNOI2013]切糕(最小割) bzoj Luogu 题面描述见上 题解时间 一开始我真就把这玩意所说的切面当成了平面来做的 事实上只是说相邻的切点高度差都不超过 $ d $ 对 ...

  10. java实现稀疏矩阵的压缩与解压

    任务要求 把棋盘当作一个稀疏矩阵,0表示没棋,1表示黑棋,2表示蓝棋. 把该稀疏矩阵压缩以三元组形式表示并以文件形式保存,再写另一个程序读取文件中的信息把压缩后的三元组还原成原来的稀疏矩阵. 其中三元 ...