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代码
  1. export function init(wrapper, options) {
  2. console.log('start handwritten');
  3. /**
  4. * 格式化日期.
  5. */
  6. Date.prototype.format = function (fmt) {
  7. var o = {
  8. "M+": this.getMonth() + 1, //月份
  9. "d+": this.getDate(), //日
  10. "h+": this.getHours(), //小时
  11. "m+": this.getMinutes(), //分
  12. "s+": this.getSeconds(), //秒
  13. "q+": Math.floor((this.getMonth() + 3) / 3), //季度
  14. "S": this.getMilliseconds() //毫秒
  15. };
  16. if (/(y+)/.test(fmt)) {
  17. fmt = fmt.replace(RegExp.$1, (this.getFullYear() + "").substr(4 - RegExp.$1.length));
  18. }
  19. for (var k in o) {
  20. if (new RegExp("(" + k + ")").test(fmt)) {
  21. fmt = fmt.replace(RegExp.$1, (RegExp.$1.length == 1) ?
  22. (o[k]) : (("00" + o[k]).substr(("" + o[k]).length)));
  23. }
  24. }
  25. return fmt;
  26. }
  27. /**
  28. * 获取URL参数
  29. */
  30. function getQueryString(name) {
  31. var reg = new RegExp("(^|&)" + name + "=([^&]*)(&|$)", "i");
  32. var r = window.location.search.substr(1).match(reg);
  33. if (r != null) return unescape(r[2]); return null;
  34. }
  35. /**
  36. * 是否数字
  37. */
  38. function isNumeric(n) {
  39. return !isNaN(parseFloat(n)) && isFinite(n);
  40. }
  41. function myRedirect(nextw) {
  42. event.returnValue = false;//加这句
  43. this.location.href = nextw;
  44. }
  45. //当页面高度超过设备可见高度时,阻止掉touchmove事件。
  46. document.body.addEventListener('touchmove', function (e) {
  47. e.preventDefault(); //阻止默认的处理方式(阻止下拉滑动的效果)
  48. }, { passive: false }); //passive 参数不能省略,用来兼容ios和android
  49. new lineCanvas({
  50. el: document.getElementById("canvas"), //绘制canvas的父级div
  51. clearEl: document.getElementById("clearCanvas"), //清除按钮
  52. saveEl: document.getElementById("saveCanvas"), //保存按钮
  53. // linewidth:1,//线条粗细,选填
  54. // color:"black",//线条颜色,选填
  55. // background:"#ffffff"//线条背景,选填
  56. });
  57. function lineCanvas(obj) {
  58. this.linewidth = 1;
  59. this.color = "#000000";
  60. this.background = "#ffffff";
  61. for (var i in obj) {
  62. this[i] = obj[i];
  63. };
  64. this.canvas = document.createElement("canvas");
  65. this.el.appendChild(this.canvas);
  66. this.cxt = this.canvas.getContext("2d");
  67. this.canvas.width = this.el.clientWidth;
  68. this.canvas.height = this.el.clientHeight;
  69. this.cxt.fillStyle = this.background;
  70. this.cxt.fillRect(0, 0, this.canvas.width, this.canvas.height);
  71. //this.cxt.fillStyle = "red";
  72. //this.cxt.font = "16px verdana";
  73. //this.cxt.textAlign = "left";
  74. ////fillText("要添加的文字",x0坐标,y0坐标)
  75. //var orderedtime = new Date().getTime();
  76. //orderedtime = (new Date(orderedtime)).format("yyyy-MM-dd hh:mm");
  77. //this.cxt.fillText(orderedtime, 30, 30);
  78. this.cxt.fillStyle = this.background;
  79. this.cxt.strokeStyle = this.color;
  80. this.cxt.lineWidth = this.linewidth;
  81. this.cxt.lineCap = "round";
  82. //开始绘制
  83. this.canvas.addEventListener("touchstart", function (e) {
  84. this.cxt.beginPath();
  85. this.cxt.moveTo(e.changedTouches[0].pageX, e.changedTouches[0].pageY);
  86. }.bind(this), false);
  87. //绘制中
  88. this.canvas.addEventListener("touchmove", function (e) {
  89. this.cxt.lineTo(e.changedTouches[0].pageX, e.changedTouches[0].pageY);
  90. this.cxt.stroke();
  91. }.bind(this), false);
  92. //结束绘制
  93. this.canvas.addEventListener("touchend", function () {
  94. this.cxt.closePath();
  95. }.bind(this), false);
  96. //清除画布
  97. this.clearEl.addEventListener("click", function () {
  98. this.cxt.clearRect(0, 0, this.canvas.width, this.canvas.height);
  99. }.bind(this), false);
  100. //保存图片,直接转base64
  101. this.saveEl.addEventListener("click", function () {
  102. var imgBase64 = this.canvas.toDataURL();
  103. console.log(imgBase64);
  104. return wrapper.invokeMethodAsync("invokeFromJS", imgBase64);
  105. }.bind(this), false);
  106. //添加日期时间
  107. function adddatetime() {
  108. this.cxt.fillStyle = "red";
  109. this.cxt.font = "12px '微软雅黑'";
  110. this.cxt.textAlign = "left";
  111. //fillText("要添加的文字",x0坐标,y0坐标)
  112. var orderedtime = new Date().getTime();
  113. orderedtime = (new Date(orderedtime)).format("yyyy-MM-dd hh:mm");
  114. this.cxt.strokeText(orderedtime, 50, 100);
  115. }
  116. };
  117. }
  118. export function destroy(options) {
  119. }
5. 编写 handwritten.css 文件. (细心的朋友应该发现,跟Day1不一样,这个css放在lib里面,留着大家思考 :-> )
handwritten.css代码
  1. #canvas {
  2. width: 99%;
  3. /*max-width: 375px;*/
  4. height: 300px;
  5. position: relative;
  6. overflow: hidden;
  7. overflow: -Scroll;
  8. }
  9. #canvas canvas {
  10. display: block;
  11. }
  12. #clearCanvas0 {
  13. width: calc(50% - 5px);
  14. height: 40px;
  15. line-height: 40px;
  16. text-align: center;
  17. position: absolute;
  18. top: 300px;
  19. left: 5px;
  20. border: 1px solid #DEDEDE;
  21. z-index: 1;
  22. }
  23. #saveCanvas0 {
  24. width: calc(50% - 5px);
  25. height: 40px;
  26. line-height: 40px;
  27. text-align: center;
  28. position: absolute;
  29. top: 300px;
  30. right: 5px;
  31. border: 1px solid #DEDEDE;
  32. z-index: 1;
  33. }
6. 点开或者新建Components文件夹 , 新建Handwritten.razor组件,签名会直接转化为Base64编码的string,同学们自己保存到数据库或者当作变量传递就行

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

Handwritten.razor代码
  1. @implements IAsyncDisposable
  2. @namespace Blazor100.Components
  3. @inject IJSRuntime JS
  4. <link href="lib/handwritten/handwritten.css" rel="stylesheet" />
  5. <div class="modal alert-popup" tabindex="-1" style="display:block" role="dialog">
  6. <div class="modal-dialog-w100">
  7. <div class="modal-content">
  8. <!-- Edit form for the current item -->
  9. <div id="canvas" style="height: 300px;">
  10. </div>
  11. <div>
  12. <button class="btn btn-secondary p-2 m-1 w-25" id="clearCanvas">清除</button>
  13. <button class="btn btn-primary p-2 m-1 w-25" id="saveCanvas">保存</button>
  14. </div>
  15. </div>
  16. </div>
  17. </div>
  18. @Result
  19. @code {
  20. /// <summary>
  21. /// Handwritten 手写签名
  22. /// </summary>
  23. [Parameter]
  24. public EventCallback<string> HandwrittenBase64 { get; set; }
  25. /// <summary>
  26. /// 关闭扫码框回调方法
  27. /// </summary>
  28. [Parameter]
  29. public EventCallback Close { get; set; }
  30. /// <summary>
  31. /// 签名结果,签名会直接转化为Base64编码的string,保存到数据库或者当作变量传递都可以
  32. /// </summary>
  33. [Parameter]
  34. public string? Result { get; set; }
  35. private IJSObjectReference? module;
  36. // To prevent making JavaScript interop calls during prerendering
  37. protected override async Task OnAfterRenderAsync(bool firstRender)
  38. {
  39. if (!firstRender) return;
  40. module = await JS.InvokeAsync<IJSObjectReference>("import", "./lib/handwritten/handwritten.js");
  41. await module.InvokeVoidAsync("init", DotNetObjectReference.Create(this), null);
  42. }
  43. [JSInvokable("invokeFromJS")]
  44. public async Task ChangeValue(string val)
  45. {
  46. Result = val;
  47. StateHasChanged();
  48. await HandwrittenBase64.InvokeAsync(val);
  49. //return Task.CompletedTask;
  50. }
  51. async ValueTask IAsyncDisposable.DisposeAsync()
  52. {
  53. if (module is not null)
  54. {
  55. //await module.InvokeVoidAsync("destroy",null);
  56. await module.DisposeAsync();
  57. }
  58. }
  59. }
7. Pages文件添加HandwrittenPage.razor文件,用于演示组件调用.
HandwrittenPage.razor代码
  1. @page "/handwritten"
  2. <h3>Handwritten 手写签名</h3>
  3. <h6>注意:只支持移动设备签名,桌面版浏览器测试请打开F12模拟为移动设备.</h6>
  4. <button class="btn btn-primary"
  5. type="button"
  6. @onclick="(() => ShowHandwritten = !ShowHandwritten)">
  7. [签名]
  8. </button>
  9. <textarea type="text" class="form-control" style="min-width: 100px;" rows="10"
  10. @bind="DrawBase64"
  11. placeholder="Base64" />
  12. @if (ShowHandwritten)
  13. {
  14. <Handwritten HandwrittenBase64="(e => { DrawBase64=e; ShowHandwritten = !ShowHandwritten; })"
  15. Close="(()=>ShowHandwritten=!ShowHandwritten)" />
  16. }
  17. @code{
  18. /// <summary>
  19. /// 显示签名界面
  20. /// </summary>
  21. bool ShowHandwritten { get; set; } = false;
  22. /// <summary>
  23. /// 签名Base64
  24. /// </summary>
  25. public string? DrawBase64 { get; set; }
  26. }
8. _Imports.razor加入一行引用组件的命名空间,已经有这行就不需要再重复写了.
  1. @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. 微信小程序+laravel 7+ Redis +短信宝 实现手机号验证码登录

    以下代码可以进行优化和封装:这里我实现功能为主,就不封装啦.小伙伴可以自己试着封装一下. 1:书写登录表单 <view class="container"> <v ...

  2. tp6 验证方式

    think验证方式

  3. thinkphp 用户登录记录日记

    1.设计数据库表名,字段 2,建立模型 <?php namespace app\login\model; use think\Model; class LoginLon extends Mode ...

  4. HBase海量数据高效入仓解决方案

    一.方案背景 现阶段部分业务数据存储在HBase中,这部分数据体量较大,达到数十亿.大数据需要增量同步这部分业务数据到数据仓库中,进行离线分析,目前主要的同步方式是通过HBase的hive映射表来实现 ...

  5. GO语言基础(结构+语法+类型+变量)

    GO语言基础(结构+语法+类型+变量) Go语言结构 Go语言语法 Go语言类型 Go语言变量       Go 语言结构 Go 语言的基础组成有以下几个部分: 包声明 引入包 函数 变量 语句 &a ...

  6. vue-cli项目创建步骤

    vue-cli项目创建步骤: 1.cmd打开命令行窗口 2.输入cnpm install vue-cli -g,然后回车等待(想在哪个目录建立vue项目就要在进入到对应目录再输入命令) 3.安装结束后 ...

  7. AE初步

    AE开发就是我们常说的ArcEngine二次开发. 1.配置环境 目前来讲,稳定的版本配置,一般配置为VS2012+ArcEngine10.2. 安装ArcEngine时,安装图中三项即可,顺序为Ar ...

  8. Java基础——Math类

    Math包含执行基本数字运算的方法 没有构造方法的情况下如何使用类中的成员? 看类的成员是否都是静态的,是的话可以直接通过类名调用 Mathl类的常用方法: 方法名 说明 public static ...

  9. Linux详解 --- 进程管理

    镜像下载.域名解析.时间同步请点击 阿里云开源镜像站 进程管理一览 接下来的几篇博客,我将主要按照这个思维导图的划分去进行讲解. 管理 在理解什么是进程管理之前,我想我们可以先理解一下什么是管理! 问 ...

  10. # Redhat7 安装 yum源

    第一步:先卸载原来的yum rpm -qa |grep yum 查看原来是否安装 yum-3.4.3-118.el7.noarch yum-utils-1.1.31-24.el7.noarch yum ...