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

本文基础步骤参考前两篇文章

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

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

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

+zxing
|-qrcode.min.js
|-zxing.min.js

2. 添加zxingjs.js文件

+zxing
|-zxingjs.js
zxingjs.js代码
import '/lib/zxing/zxing.min.js';
var codeReader = null;
export function init(autostop, wrapper, options) {
console.log('autostop' + autostop); let selectedDeviceId;
//const codeReader = new ZXing.BrowserBarcodeReader()
codeReader = new ZXing.BrowserMultiFormatReader()
console.log('ZXing code reader initialized')
codeReader.getVideoInputDevices()
.then((videoInputDevices) => {
const sourceSelect = document.getElementById('sourceSelect')
selectedDeviceId = videoInputDevices[0].deviceId
console.log('videoInputDevices:' + videoInputDevices.length);
if (videoInputDevices.length > 1) {
videoInputDevices.forEach((element) => {
const sourceOption = document.createElement('option')
sourceOption.text = element.label
sourceOption.value = element.deviceId
sourceSelect.appendChild(sourceOption)
selectedDeviceId = element.deviceId;
}) sourceSelect.onchange = () => {
selectedDeviceId = sourceSelect.value;
codeReader.reset();
StartScan();
} const sourceSelectPanel = document.getElementById('sourceSelectPanel')
sourceSelectPanel.style.display = 'block'
} StartScan(autostop); document.getElementById('startButton').addEventListener('click', () => {
StartScan();
}) function StartScan(autostop) {
codeReader.decodeOnceFromVideoDevice(selectedDeviceId, 'video').then((result) => {
console.log(result)
document.getElementById('result').textContent = result.text var supportsVibrate = "vibrate" in navigator;
if (supportsVibrate) navigator.vibrate(1000); if (autostop) {
console.log('autostop');
codeReader.reset();
return wrapper.invokeMethodAsync("invokeFromJS", result.text);
} else {
console.log('None-stop');
codeReader.reset();
wrapper.invokeMethodAsync("invokeFromJS", result.text);
} }).catch((err) => {
console.error(err)
document.getElementById('result').textContent = err
})
console.log(`Started continous decode from camera with id ${selectedDeviceId}`)
} document.getElementById('resetButton').addEventListener('click', () => {
document.getElementById('result').textContent = '';
codeReader.reset();
console.log('Reset.')
}) document.getElementById('closeButton').addEventListener('click', () => {
document.getElementById('result').textContent = '';
codeReader.reset();
console.log('closeButton.')
wrapper.invokeMethodAsync("invokeFromJSClose");
}) })
.catch((err) => {
console.error(err)
})
}
export function destroy(options) {
if (undefined !== codeReader && null !== codeReader && options.id == codeReader.element.id) {
codeReader.destroy();
console.log(codeReader.element.id, 'destroy');
}
}

3. 前面两篇文章主要在于快速入手建立组件, 基本没有解释代码. 现在开始穿插一点Blazor和JS交互的相关知识.

3.1 打开Day1的Pages/ViewerPage.razor文件,顶端有一句 @page "/viewer" , 意思是此页面的路由地址为viewer,请求此路径就会加载到此页面/组件.

参考阅读:ASP.NET Core Blazor 路由和导航

同理,Pages/HandwrittenPage.razor文件的 @page "/handwritten" 也是一样作用

3.2 调用组件演示页面代码逐行说明
<Viewerjs Images="imagesList" /> 直接调用Viewerjs组件,Images是组件的参数,打开文件Components/Viewerjs.razor可以查看定义
    /// <summary>
/// 图片列表
/// </summary>
[Parameter] public List<string> Images { get; set; } = new List<string>();

@page "/viewer"  //页面的路由地址

<Viewerjs Images="imagesList" /> //调用Viewerjs组件,指定组件图片列表数据来源

@code{
List<string>? imagesList; protected override void OnInitialized() //组件初始化 , [参考阅读:组件生命周期](https://docs.microsoft.com/zh-cn/aspnet/core/blazor/components/lifecycle?view=aspnetcore-6.0)
{
//生成演示图片数据 imagesList = new List<string>();
if (!imagesList.Any())
{
for (int i = 1; i <= 9; i++)
{
imagesList.Add($"https://fengyuanchen.github.io/viewerjs/images/thumbnails/tibet-{i}.jpg");
}
}
} }

3.3 组件生命周期

参考阅读:组件生命周期

3.4 调整演示工程外观

现在Pages/Index.razor已经直接放置了两个占用空间比较大的组件,再加入今天的组件势必很难看,我们将对首页以及左侧导航菜单做一些调整,以便条理更加清晰.

删除Pages/Index.razor文件中以下代码

<ViewerPage />

<hr />

<HandwrittenPage />

打开Shared/NavMenu.razor添加相关导航,NavLink组件是Blazor默认自带导航组件, 参考阅读:NavLink 类

        <div class="nav-item px-3">
<NavLink class="nav-link" href="viewer">
<span class="oi oi-plus" aria-hidden="true"></span> 图片浏览
</NavLink>
</div>
<div class="nav-item px-3">
<NavLink class="nav-link" href="handwritten">
<span class="oi oi-plus" aria-hidden="true"></span> 手写签名
</NavLink>
</div>
<div class="nav-item px-3">
<NavLink class="nav-link" href="barcodescanner">
<span class="oi oi-plus" aria-hidden="true"></span> 条码扫描
</NavLink>
</div>

5. 打开Components文件夹 , 新建BarcodeScanner.razor组件

参考阅读:Blazor JS 互操作

参考阅读:JS 模块中的 JS 隔离

5.1 C#组件实例封装
DotNetObjectReference.Create(this)
5.2 C#标记JS调用的函数[JSInvokable("invokeFromJS")]
    [JSInvokable("invokeFromJS")]
public async Task ChangeValue(string val)
{
Result = val;
StateHasChanged();
await ScanResult.InvokeAsync(val);
}
5.3 zxingjs.js文件
import '/lib/zxing/zxing.min.js' //模块的方式加载zxing库

//定义一个函数init供blazor组件调用

export function init(autostop, wrapper, options) {}  //wrapper为blazor组件的实例 

//扫码结果通过blazor组件的实例调用DotNet.invokeMethodAsync实现

wrapper.invokeMethodAsync("invokeFromJS", result.text);

5.4 C#动态载入JS模块
private IJSObjectReference? module;

module = await JS.InvokeAsync<IJSObjectReference>("import", "./lib/zxing/zxingjs.js");

5.5 C#调用JS函数
module.InvokeVoidAsync("init", true, DotNetObjectReference.Create(this), null);
5.6 完整代码
BarcodeScanner.razor代码
@implements IAsyncDisposable
@namespace Blazor100.Components
@inject IJSRuntime JS <div class="modal alert-popup" tabindex="-1" style="display:block" role="dialog">
<div class="modal-dialog">
<div class="modal-content">
<!-- Edit form for the current item -->
<div class="modal-body"> <button class="btn btn-primary p-2 m-1 w-25" id="startButton">@ScanBtnTitle</button>
<button class="btn btn-secondary p-2 m-1 w-25" id="resetButton">@ResetBtnTitle</button>
<button type="button" class="btn btn-info p-2 m-1 w-25" id="closeButton">@CloseBtnTitle</button> <div id="sourceSelectPanel" style="display:none">
<label for="sourceSelect">@SelectDeviceBtnTitle:</label><span class="text-dark" id="result"></span>
<select id="sourceSelect" style="max-width:100%" class="form-control">
</select>
</div>
<div>
<video id="video" style="min-height:150px;max-height:60%; max-width: 100%;border: 1px solid gray"></video>
</div> </div>
</div>
</div>
</div>
@Result @code {
/// <summary>
/// BarcodeScanner 条码扫描
/// </summary> /// <summary>
/// 扫码按钮文本/Scan button title
/// </summary>
[Parameter]
public string ScanBtnTitle { get; set; } = "扫码"; /// <summary>
/// 复位按钮文本/Reset button title
/// </summary>
[Parameter]
public string ResetBtnTitle { get; set; } = "复位"; /// <summary>
/// 关闭按钮文本/Close button title
/// </summary>
[Parameter]
public string CloseBtnTitle { get; set; } = "关闭"; /// <summary>
/// 选择设备按钮文本/Select device button title
/// </summary>
[Parameter]
public string SelectDeviceBtnTitle { get; set; } = "选择设备"; /// <summary>
/// 扫码结果回调方法/Scan result callback method
/// </summary>
[Parameter]
public EventCallback<string> ScanResult { get; set; } /// <summary>
/// 关闭扫码框回调方法/Close scan code callback method
/// </summary>
[Parameter]
public EventCallback Close { get; set; } /// <summary>
/// 扫码结果/Scan result
/// </summary>
[Parameter]
public string? Result { get; set; } /// <summary>
/// 显示扫码框/Show scan box
/// </summary>
[Parameter]
public bool ShowScanBarcode { get; set; } private IJSObjectReference? module; // To prevent making JavaScript interop calls during prerendering
protected override async Task OnAfterRenderAsync(bool firstRender)
{
try
{
if (!firstRender) return;
module = await JS.InvokeAsync<IJSObjectReference>("import", "./lib/zxing/zxingjs.js");
await module.InvokeVoidAsync("init", true, DotNetObjectReference.Create(this), null); //组件实例封装:DotNetObjectReference.Create(this)
}
catch (Exception e)
{
if (OnError != null) await OnError.Invoke(e.Message);
} } [JSInvokable("invokeFromJS")]
public async Task ChangeValue(string val)
{
Result = val;
StateHasChanged();
await ScanResult.InvokeAsync(val);
} [JSInvokable("invokeFromJSClose")]
public async Task CloseScan()
{
await Close.InvokeAsync(null);
} /// <summary>
/// 获得/设置 错误回调方法
/// </summary>
[Parameter]
public Func<string, Task>? OnError { get; set; } async ValueTask IAsyncDisposable.DisposeAsync()
{
if (module is not null)
{
//await module.InvokeVoidAsync("destroy", Options);
await module.DisposeAsync();
}
} }
6. Pages文件添加BarcodeScannerPage.razor文件,用于演示组件调用.
BarcodeScannerPage.razor代码
@page "/barcodescanner"

<h3>条码扫描 BarcodeReader</h3>

<h4>扫描条码/QR码。</h4>

<button class="btn btn-primary"
type="button"
@onclick="(() => ShowScanBarcode = !ShowScanBarcode)">
扫码
</button>
<input type="text" class="form-control" style="min-width: 100px;"
@bind-value="BarCode"
placeholder="条码" />
@if (ShowScanBarcode)
{ <BarcodeScanner ScanResult="((e) => { BarCode=e; ShowScanBarcode = !ShowScanBarcode; })"
ShowScanBarcode="ShowScanBarcode"
Close="(()=>ShowScanBarcode=!ShowScanBarcode)" /> } <p>@message</p> @code{ /// <summary>
/// 显示扫码界面
/// </summary>
bool ShowScanBarcode { get; set; } = false; /// <summary>
/// 条码
/// </summary>
public string? BarCode { get; set; } private string? message; private Task OnError(string message)
{
this.message = message;
StateHasChanged();
return Task.CompletedTask;
} }

7. _Imports.razor加入一行引用组件的命名空间,已经有这行就不需要再重复写了.

@using Blazor100.Components

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

        <div class="nav-item px-3">
<NavLink class="nav-link" href="barcodescanner">
<span class="oi oi-plus" aria-hidden="true"></span> 条码扫描
</NavLink>
</div>

9. F5运行程序

至此,使用JS隔离封装ZXing扫码组件大功告成! 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隔离封装ZXing扫码的更多相关文章

  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隔离封装signature_pad签名组件

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

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

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

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

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

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

    Blazor组件自做二 : 使用JS隔离制作手写签名组件 本文相关参考链接 JavaScript 模块中的 JavaScript 隔离 Viewer.js工程 Blazor组件自做一 : 使用JS隔离 ...

  7. Blazor组件自做九: 用20行代码实现文件上传,浏览目录功能 (3)

    接上篇 Blazor组件自做九: 用20行代码实现文件上传,浏览目录功能 (2) 7. 使用配置文件指定监听地址 打开 appsettings.json 文件,加入一行 "UseUrls&q ...

  8. Blazor组件自做十一 : File System Access 文件系统访问 组件

    Blazor File System Access 文件系统访问 组件 Web 应用程序与用户本地设备上的文件进行交互 File System Access API(以前称为 Native File ...

  9. 定时组件quartz系列<三>quartz调度机制调研及源码分析

    quartz2.2.1集群调度机制调研及源码分析引言quartz集群架构调度器实例化调度过程触发器的获取触发trigger:Job执行过程:总结:附: 引言 quratz是目前最为成熟,使用最广泛的j ...

随机推荐

  1. 基于Spring Boot的线程池监控方案

    前言 这篇是推动大家异步编程的思想的线程池的准备篇,要做好监控,让大家使用无后顾之忧,敬畏生产. 为什么需要对线程池进行监控 Java线程池作为最常使用到的并发工具,相信大家都不陌生,但是你真的确定使 ...

  2. mixin混入

    mixin(混入) 功能:可以把多个组件共用的配置提取成一个混入对象 使用方式: 第一步定义混合,例如: { data(){.........}, methods:{.........} ...... ...

  3. 2022年官网下安装MongoDB最全版与官网查阅方法(5.0.6)

    一.下载安装 1.百度搜索,找到官网,或直接访问:https://www.mongodb.com/ 2.寻找下载位置,双击下载. 3.找到本地位置,双击执行,进入欢迎界面,选择next. 4.勾选协议 ...

  4. UOJ188题解

    我们先枚举一个最大质因子,然后设 \(dp[n][k]\) 为 \(n\) 以内使用了 \(pri[k]\) 以内的质数的数的最大质因子之和,答案就是: \[\sum_{k\leq n}dp[\lfl ...

  5. 如何取消以太坊智能合约授权,防止被黑客盗取Token?

    在小狐狸钱包(MetaMask)日常使用中,有一个细节可能很少人注意到,就是无论你登入什么网站,或者需要跟任何项目签订智能合约都要授权的步骤,这其中就会给黑客留下很多空子,特别是将一个Token用智能 ...

  6. Web网站建站过程(白嫖)——域名

    目录 1.域名注册商(选一个吧) 2.域名注册 没有域名建啥站? 1.域名注册商(选一个吧) 到时候你们就会想起: ...... 但是我们不用上面的,因为上面的太费Q,我们要用的是-- 2.域名注册 ...

  7. 编程篇——Java学习路线

    1.java基础编程2.Java多线程编程(并发)3.Java设计模式(重构)4.Java调试技术(Java虚拟机)5.Java常用框架学习篇6.Java开发之web篇

  8. SpringBoot在线预览PDF文件(引用pdf.js工具)

    本项目Demo使用了PDF.js插件实现PDF在线阅读功能PDF.js插件下载地址 实测能用! 1.创建SpringBoot项目,目录结构如下: 2.进行项目配置: pom.xml: <proj ...

  9. Struts2搭建及利用OGNL表达式弹出计算器

    0x01 环境搭建 1.创建Struts2应用 创建一个动态网站项目 2.配置Tomcat启动环境 3.在WebContent目录下的WEB-INF文件夹中创建web.xml,Tomcat启动时会加载 ...

  10. GO后端开发+VUE实列

    因为我是从java转到go,代码结构跟我之前用java的很像 在这里只浅显的实战运用,没有过多理论讲解 工作环境:IDE:Goland , Go 1.17.7 框架 Gin+Gorm ,前端VUE 这 ...