前言:
此时各位老铁们对“js调用打印”都比较讲究,大家都需要知道一些“js调用打印”的相关资讯。那么小编同时在网络上汇集了一些关于“js调用打印””的相关内容,希望各位老铁们能喜欢,朋友们一起来了解一下吧!各位,好久不见,这段时间事情太多了,一直没空更新文章,sosososorry.
如果我告诉您网站能以安全和隐私保护的方式与附近的蓝牙设备进行通信,您会怎么想?如此一来,心率监测器、会唱歌的灯,甚至海龟都可以直接与网站交互了。到目前为止,仅有部分针对特定平台的应用可以实现与蓝牙设备的交互。Web Bluetooth API 旨在改变这一现状,以期将此功能赋予 Web 浏览器。笔者所在的POS行业更是经常用到各种蓝牙小票机,蓝牙标签机,如此一来整个 Blazor ,app客户端都不用了, 很是利好啊! 话不多说,开整!
原文链接:
1. 运行截图
演示地址 DemoSSR
连接设备
连接成功
打印标签
我测试这台打印机使用cpcl语言,测试的指令是
! 10 200 200 400 1BEEP 1PW 380SETMAG 1 1CENTERTEXT 10 2 10 40 Micro BarTEXT 12 3 10 75 BlazorTEXT 10 2 10 350 eMenuB QR 30 150 M 2 U 7MA,2. 源码大家参考开源地址,仅摘抄要点和写组件使用方式
本组件主要是调用浏览器API实现基于浏览器的蓝牙功能,现代桌面和安卓移动端都支持.包括MAUI Blazor
navigator.bluetooth.requestDevice2.1 关键js代码
async function onConnect() { bluetoothDevice = null; if (opt.serviceUuid && opt.serviceUuid.toString().startsWith('0x')) { opt.serviceUuid = parseInt(opt.serviceUuid); } if (opt.characteristicUuid && opt.characteristicUuid.toString().startsWith('0x')) { opt.characteristicUuid = parseInt(opt.characteristicUuid); } try { logII('Requesting any Bluetooth Device...'); var option = { //acceptAllDevices: true, //"filters": [{ // "namePrefix": "BMAU" //}], optionalServices: [opt.serviceUuid] } if (opt.namePrefix) option.filters = '[{ "namePrefix": "' + opt.namePrefix + '"}]'; else option.acceptAllDevices = true; bluetoothDevice = await navigator.bluetooth.requestDevice(option); bluetoothDevice.addEventListener('gattserverdisconnected', onDisconnected); await connect(); } catch (error) { logErr('Argh! ' + error); } } async function connect() { exponentialBackoff(3 /* max retries */, 2 /* seconds delay */, async function toTry() { time('Connecting to Bluetooth Device... '); logII('Connecting to GATT Server...'); logII('> Name: ' + bluetoothDevice.name); logII('> Id: ' + bluetoothDevice.id); opt.devicename = bluetoothDevice.name; opt.deviceID = bluetoothDevice.id; wrapper.invokeMethodAsync('GetResult', opt, "连接中..."); wrapper.invokeMethodAsync('UpdateError', ''); const server = await bluetoothDevice.gatt.connect(); logII('Getting Services...'); const services = await server.getPrimaryServices(); logII('Getting Characteristics...'); for (const service of services) { logII('> Service: ' + service.uuid); const characteristics = await service.getCharacteristics(); characteristics.forEach(characteristic => { if (getSupportedPropertiesWrite(characteristic)) { logII('>> Characteristic: ' + characteristic.uuid); opt.characteristicUuid = characteristic.uuid; myDescriptor = characteristic; return; } }); if (opt.characteristicUuid) { if (tools) tools.classList.remove('hidden'); if (btnDisconnect) btnDisconnect.classList.remove('hidden'); if (btnReconnect) btnReconnect.classList.remove('hidden'); wrapper.invokeMethodAsync('GetResult', opt, "已连接"); wrapper.invokeMethodAsync('UpdateError', ''); return; } } }, function success() { logII(`> Bluetooth Device ${bluetoothDevice.name} connected. `); }, function fail() { time('Failed to reconnect.'); }); }2.2 组件页面发送指令执行.
其中我设置的MaxChunk是100,如果安卓平台出现打印不全等莫名故障,可以把MaxChunk设置为20试试.具体请自行百度.
WriteChunk(commands); async function WriteChunk(string) { if (!myDescriptor && !serialWriter) { console.log(' > !myDescriptor serialWriter null!'); return; } console.log('WriteChunk', string); var buffer = GBK.encode(string); var buffer1 = new Uint8Array(buffer).buffer; for (let i = 0, j = 0, length = buffer1.byteLength; i < length; i += opt.maxChunk, j++) { let subPackage = buffer1.slice(i, i + opt.maxChunk <= length ? (i + opt.maxChunk) : length); await _print(subPackage); } } async function _print(buffer) { try { logII('Setting Characteristic User Description...'); console.log(buffer); if (myDescriptor) await myDescriptor.writeValue(buffer); } catch (error) { logErr('Argh! ' + error); } try { if (serialWriter) { await serialWriter.write(buffer); } } catch (error) { logErr('Argh! ' + error); } }3. Demo工程页面
工程引用 BootstrapBlazor.Bluetooth 包
_Imports.razor加入一行 @using BootstrapBlazor.Components
3.1 新建PrintDemo.razor测试页
完整例子
razor代码
<Printer @ref="printer" OnResult="OnResult" OnError="OnError" OnUpdateStatus="OnUpdateStatus" OnUpdateError="OnError" OnGetDevices="OnGetDevices" /> <div @ref="printer.PrinterElement"> <button data-action="btnConnect" class="btn btn-outline-primary">连接</button> <button data-action="btnDisconnect" class="btn btn-outline-danger">断开</button> @*<button data-action="btnReconnect" class="btn btn-outline-secondary">重连</button>*@ <button data-action="tools" class="btn btn-outline-primary" @onclick="printer.Print">@printer.PrintButtonText</button></div><pre>@message</pre><pre style="color:green">@statusmessage</pre><pre style="color:red">@errmessage</pre><p/>3.2 cs代码
@code{ Printer printer { get; set; } = new Printer(); /// <summary> /// 显示内置界面 /// </summary> bool ShowUI { get; set; } = false; private string? message; private string? statusmessage; private string? errmessage; private Task OnResult(string message) { this.message = message; StateHasChanged(); return Task.CompletedTask; } private Task OnUpdateStatus(string message) { this.statusmessage = message; StateHasChanged(); return Task.CompletedTask; } private Task OnError(string message) { this.errmessage = message; StateHasChanged(); return Task.CompletedTask; } private Task OnGetDevices(List<string>? devices) { this.message = ""; if (devices == null || devices.Count == 0) return Task.CompletedTask; this.message += $"已配对设备{devices.Count}:{Environment.NewLine}"; devices.ForEach(a => this.message += $" {a}{Environment.NewLine}"); //this.message = this.message.Replace(Environment.NewLine, "<br/>"); StateHasChanged(); return Task.CompletedTask; } }
内置的其他两个组件介绍
4. 蓝牙设备电量组件
完整例子
<button class="btn btn-outline-secondary" @onclick="GetBatteryLevel ">查询电量</button><BatteryLevel @ref="batteryLevel" OnUpdateValue="OnUpdateValue" OnUpdateStatus="OnUpdateStatus" OnUpdateError="OnError" /><br/><progress max="100" value="@value"> @value % </progress><pre>@message</pre><pre style="color:green">@statusmessage</pre><pre style="color:red">@errmessage</pre>@code{ BatteryLevel batteryLevel { get; set; } = new BatteryLevel(); private decimal? value=0; private string? message; private string? statusmessage; private string? errmessage; private Task OnResult(string message) { this.message = message; StateHasChanged(); return Task.CompletedTask; } private Task OnUpdateValue(decimal value) { this.value = value; this.statusmessage = $"设备电量{value}%"; StateHasChanged(); return Task.CompletedTask; } private Task OnUpdateStatus(BluetoothDevice device) { this.statusmessage = device.Status; StateHasChanged(); return Task.CompletedTask; } private Task OnError(string message) { this.errmessage = message; StateHasChanged(); return Task.CompletedTask; } public async void GetBatteryLevel() { await batteryLevel.GetBatteryLevel(); }}5. 蓝牙设备电量组件
完整例子
<button class="btn btn-outline-secondary" @onclick="GetHeartrate ">查询心率</button><button class="btn btn-outline-secondary" @onclick="StopHeartrate ">停止读取</button><Heartrate @ref="heartrate" OnUpdateValue="OnUpdateValue" OnUpdateStatus="OnUpdateStatus" OnUpdateError="OnError" /><h2 style="color:red" data-action="heartrate"/><pre>@message</pre><pre style="color:green">@statusmessage</pre><pre style="color:red">@errmessage</pre>@code{ string heartrateIcon;// { get => (heartrateIcon == "❤" ? "♥" : "❤"); } Heartrate heartrate { get; set; } = new Heartrate(); private string? message; private int? value; private string? statusmessage; private string? errmessage; private Task OnResult(string message) { this.message = message; StateHasChanged(); return Task.CompletedTask; } private Task OnUpdateValue(int value) { this.value = value; this.statusmessage = $"心率{value}"; StateHasChanged(); return Task.CompletedTask; } private Task OnUpdateStatus(BluetoothDevice device) { this.statusmessage = device.Status; StateHasChanged(); return Task.CompletedTask; } private Task OnError(string message) { this.errmessage = message; StateHasChanged(); return Task.CompletedTask; } public async void GetHeartrate() { await heartrate.GetHeartrate(); } public async void StopHeartrate() { await heartrate.StopHeartrate(); }}其他资料
Web Bluetooth API 网站通过 JavaScript 与蓝牙设备进行通信 ,在Windows下水土不服解决办法 - AlexChow - 博客园
Bluetooth组件源码
Blazor组件自做系列
Blazor组件自做一 : 使用JS隔离封装viewerjs库
Blazor组件自做二 : 使用JS隔离制作手写签名组件
Blazor组件自做三 : 使用JS隔离封装ZXing扫码
Blazor组件自做四: 使用JS隔离封装signature_pad签名组件
Blazor组件自做五: 使用JS隔离封装Google地图
Blazor组件自做六: 使用JS隔离封装Baidu地图
Blazor组件自做七: 使用JS隔离制作定位/持续定位组件
Blazor组件自做八: 使用JS隔离封装屏幕键盘kioskboard.js组件
Blazor组件自做九: 使用JS隔离制作蓝牙打印组件(通用跨平台隔空打印小票/标签方案)
知识共享许可协议
本作品采用 知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议 进行许可。欢迎转载、使用、重新发布,但务必保留文章署名AlexChow(包含链接: ),不得用于商业目的,基于本文修改后的作品务必以相同的许可发布。如有任何疑问,请与我联系 。