!2671 feat(#I537X5): remove zxing.min.js from bundle.min.js

* refactor: 更新打包文件名
* feat: BarcodeReader 增加动态加载功能
* feat: 增加 JSModule 扩展方法
* chore: 增加 esm 配置
* refactor: 移动 zxing 包到动态加载目录
* refactor: 移动震动脚本到扩展类中
This commit is contained in:
Argo 2022-04-18 04:48:38 +00:00
parent 5a92056a97
commit 98f2f9af60
14 changed files with 283 additions and 122 deletions

View File

@ -25,6 +25,10 @@
},
"extensionToExtension": {
"add": {
".esm.js": [
".cs",
".razor"
],
".js": [
".cs",
".razor",

View File

@ -0,0 +1,84 @@
let codeReader = null;
export function bb_barcode(el, method, auto, obj) {
var $el = $(el);
codeReader = new ZXing.BrowserMultiFormatReader();
if ($el.attr('data-scan') === 'Camera') {
codeReader.getVideoInputDevices().then((videoInputDevices) => {
obj.invokeMethodAsync("InitDevices", videoInputDevices).then(() => {
if (auto && videoInputDevices.length > 0) {
var button = $el.find('button[data-method="scan"]');
var data_method = $el.attr('data-scan');
if (data_method === 'Camera') button.trigger('click');
}
});
});
}
$el.on('click', 'button[data-method]', function () {
var data_method = $(this).attr('data-method');
if (data_method === 'scan') {
obj.invokeMethodAsync("Start");
var deviceId = $el.find('.dropdown-item.active').attr('data-val');
var video = $el.find('video').attr('id');
codeReader.decodeFromVideoDevice(deviceId, video, (result, err) => {
if (result) {
$.bb_vibrate();
console.log(result.text);
obj.invokeMethodAsync("GetResult", result.text);
var autostop = $el.attr('data-autostop') === 'true';
if (autostop) {
codeReader.reset();
}
}
if (err && !(err instanceof ZXing.NotFoundException)) {
console.error(err)
obj.invokeMethodAsync('GetError', err);
}
});
}
else if (data_method === 'scanImage') {
codeReader = new ZXing.BrowserMultiFormatReader();
$el.find(':file').remove();
var $img = $('.scanner-image');
var $file = $('<input type="file" hidden accept="image/*">');
$el.append($file);
$file.on('change', function () {
if (this.files.length === 0) {
return;
}
var reader = new FileReader();
reader.onloadend = function (e) {
$img.attr('src', e.target.result);
codeReader.decodeFromImage($img[0]).then((result) => {
if (result) {
$.bb_vibrate();
console.log(result.text);
obj.invokeMethodAsync('GetResult', result.text);
}
}).catch((err) => {
if (err) {
console.log(err)
obj.invokeMethodAsync('GetError', err.message);
}
})
};
reader.readAsDataURL(this.files[0]);
})
$file.trigger('click');
}
else if (data_method === 'close') {
codeReader.reset();
obj.invokeMethodAsync("Stop");
}
});
};
export function bb_barcode_dispose() {
if (codeReader != null) {
codeReader.reset();
}
};

View File

@ -1,94 +0,0 @@
(function ($) {
$.extend({
bb_vibrate: function () {
if ('vibrate' in window.navigator) {
window.navigator.vibrate([200, 100, 200]);
var handler = window.setTimeout(function () {
window.clearTimeout(handler);
window.navigator.vibrate([]);
}, 1000);
}
},
bb_barcode: function (el, obj, method, auto) {
var $el = $(el);
var codeReader = new ZXing.BrowserMultiFormatReader();
if (method === 'dispose') {
codeReader.reset();
return;
}
if ($el.attr('data-scan') === 'Camera') {
codeReader.getVideoInputDevices().then((videoInputDevices) => {
obj.invokeMethodAsync("InitDevices", videoInputDevices).then(() => {
if (auto && videoInputDevices.length > 0) {
var button = $el.find('button[data-method="scan"]');
var data_method = $el.attr('data-scan');
if (data_method === 'Camera') button.trigger('click');
}
});
});
}
$el.on('click', 'button[data-method]', function () {
var data_method = $(this).attr('data-method');
if (data_method === 'scan') {
obj.invokeMethodAsync("Start");
var deviceId = $el.find('.dropdown-item.active').attr('data-val');
var video = $el.find('video').attr('id');
codeReader.decodeFromVideoDevice(deviceId, video, (result, err) => {
if (result) {
$.bb_vibrate();
console.log(result.text);
obj.invokeMethodAsync("GetResult", result.text);
var autostop = $el.attr('data-autostop') === 'true';
if (autostop) {
codeReader.reset();
}
}
if (err && !(err instanceof ZXing.NotFoundException)) {
console.error(err)
obj.invokeMethodAsync('GetError', err);
}
});
}
else if (data_method === 'scanImage') {
codeReader = new ZXing.BrowserMultiFormatReader();
$el.find(':file').remove();
var $img = $('.scanner-image');
var $file = $('<input type="file" hidden accept="image/*">');
$el.append($file);
$file.on('change', function () {
if (this.files.length === 0) {
return;
}
var reader = new FileReader();
reader.onloadend = function (e) {
$img.attr('src', e.target.result);
codeReader.decodeFromImage($img[0]).then((result) => {
if (result) {
$.bb_vibrate();
console.log(result.text);
obj.invokeMethodAsync('GetResult', result.text);
}
}).catch((err) => {
if (err) {
console.log(err)
obj.invokeMethodAsync('GetError', err.message);
}
})
};
reader.readAsDataURL(this.files[0]);
})
$file.trigger('click');
}
else if (data_method === 'close') {
codeReader.reset();
obj.invokeMethodAsync("Stop");
}
});
}
});
})(jQuery);

View File

@ -13,7 +13,7 @@ namespace BootstrapBlazor.Components;
/// </summary>
public partial class BarcodeReader : IAsyncDisposable
{
private JSInterop<BarcodeReader>? Interop { get; set; }
private JSModule<BarcodeReader>? Module { get; set; }
private string AutoStopString => AutoStop ? "true" : "false";
@ -147,8 +147,8 @@ public partial class BarcodeReader : IAsyncDisposable
{
if (firstRender)
{
Interop = new JSInterop<BarcodeReader>(JSRuntime);
await Interop.InvokeVoidAsync(this, ScannerElement, "bb_barcode", "init", AutoStart);
Module = await JSRuntime.LoadModule("barcodereader.bundle.js", this);
await Module.InvokeVoidAsync("bb_barcode", ScannerElement, "init", AutoStart);
}
}
@ -222,24 +222,21 @@ public partial class BarcodeReader : IAsyncDisposable
/// DisposeAsyncCore 方法
/// </summary>
/// <param name="disposing"></param>
/// <returns></returns>
protected virtual async ValueTask DisposeAsyncCore(bool disposing)
{
if (disposing)
{
if (Interop != null)
if (Module != null)
{
await Interop.InvokeVoidAsync(this, ScannerElement, "bb_barcode", "dispose");
Interop.Dispose();
Interop = null;
await Module.InvokeVoidAsync("bb_barcode_dispose");
await Module.DisposeAsync();
}
}
}
/// <summary>
///
/// DisposeAsync 方法
/// </summary>
/// <returns></returns>
public async ValueTask DisposeAsync()
{
await DisposeAsyncCore(true);

View File

@ -81,7 +81,7 @@ internal static class JSRuntimeExtensions
}
/// <summary>
///
/// IJSRuntime 扩展方法 动态加载脚本 脚本目录为 modules
/// </summary>
/// <param name="jsRuntime"></param>
/// <param name="path"></param>
@ -93,15 +93,16 @@ internal static class JSRuntimeExtensions
}
/// <summary>
///
/// IJSRuntime 扩展方法 动态加载脚本 脚本目录为 modules
/// </summary>
/// <typeparam name="TValue"></typeparam>
/// <param name="jsRuntime"></param>
/// <param name="component"></param>
/// <param name="value"></param>
/// <param name="path"></param>
/// <returns></returns>
public static async Task<JSModule> LoadModule<TComponent>(this IJSRuntime jsRuntime, TComponent component) where TComponent : ComponentBase
public static async Task<JSModule<TValue>> LoadModule<TValue>(this IJSRuntime jsRuntime, string path, TValue value) where TValue : class
{
var fileName = $"{component.GetType().Name}.js";
var jSObjectReference = await jsRuntime.InvokeAsync<IJSObjectReference>(identifier: "import", $"./_content/BootstrapBlazor/modules/{fileName}");
return new JSModule(jSObjectReference);
var jSObjectReference = await jsRuntime.InvokeAsync<IJSObjectReference>(identifier: "import", $"./_content/BootstrapBlazor/modules/{path}");
return new JSModule<TValue>(jSObjectReference, value);
}
}

View File

@ -117,8 +117,11 @@ public class JSInterop<TValue> : IDisposable where TValue : class
{
if (disposing)
{
_objRef?.Dispose();
_objRef = null;
if (_objRef != null)
{
_objRef.Dispose();
_objRef = null;
}
}
}

View File

@ -11,11 +11,14 @@ namespace BootstrapBlazor.Components;
/// </summary>
public class JSModule : IAsyncDisposable
{
/// <summary>
/// IJSObjectReference 实例
/// </summary>
[NotNull]
private IJSObjectReference? Module { get; set; }
protected IJSObjectReference? Module { get; set; }
/// <summary>
///
/// 构造函数
/// </summary>
/// <param name="jSObjectReference"></param>
public JSModule(IJSObjectReference? jSObjectReference)
@ -24,12 +27,20 @@ public class JSModule : IAsyncDisposable
}
/// <summary>
///
/// InvokeVoidAsync 方法
/// </summary>
/// <param name="identifier"></param>
/// <param name="args"></param>
/// <returns></returns>
public ValueTask InvokeVoidAsync(string identifier, params object[] args) => Module.InvokeVoidAsync(identifier, args);
public virtual ValueTask InvokeVoidAsync(string identifier, params object?[] args) => Module.InvokeVoidAsync(identifier, args);
/// <summary>
/// InvokeVoidAsync 方法
/// </summary>
/// <param name="identifier"></param>
/// <param name="args"></param>
/// <returns></returns>
public virtual ValueTask<TValue> InvokeAsync<TValue>(string identifier, params object?[] args) => Module.InvokeAsync<TValue>(identifier, args);
/// <summary>
/// Dispose 方法
@ -56,3 +67,55 @@ public class JSModule : IAsyncDisposable
GC.SuppressFinalize(this);
}
}
/// <summary>
/// 模块加载器
/// </summary>
/// <typeparam name="TValue"></typeparam>
public class JSModule<TValue> : JSModule where TValue : class
{
/// <summary>
/// DotNetReference 实例
/// </summary>
protected DotNetObjectReference<TValue> DotNetReference { get; set; }
/// <summary>
/// 构造函数
/// </summary>
/// <param name="jSObjectReference"></param>
/// <param name="value"></param>
public JSModule(IJSObjectReference? jSObjectReference, TValue value) : base(jSObjectReference)
{
DotNetReference = DotNetObjectReference.Create(value);
}
/// <summary>
/// InvokeVoidAsync 方法
/// </summary>
/// <param name="identifier"></param>
/// <param name="args"></param>
/// <returns></returns>
public override ValueTask InvokeVoidAsync(string identifier, params object?[] args)
{
var paras = new List<object?>();
if (args != null)
{
paras.AddRange(args);
}
paras.Add(DotNetReference);
return Module.InvokeVoidAsync(identifier, paras.ToArray());
}
/// <summary>
/// Dispose 方法
/// </summary>
/// <param name="disposing"></param>
protected override ValueTask DisposeAsyncCore(bool disposing)
{
if (disposing)
{
DotNetReference.Dispose();
}
return base.DisposeAsyncCore(disposing);
}
}

View File

@ -16,7 +16,7 @@
"outputFileName": "wwwroot/js/bootstrap.blazor.min.js",
"inputFiles": [
"wwwroot/lib/extensions/*.js",
"Components/**/*.js"
"Components/**/!(*.esm).js"
],
"minify": {
"enabled": true,
@ -35,5 +35,15 @@
"enabled": false,
"renameLocals": true
}
},
{
"outputFileName": "wwwroot/modules/barcodereader.bundle.js",
"inputFiles": [
"Components/barcodereader/*.esm.js"
],
"minify": {
"enabled": false,
"renameLocals": true
}
}
]

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -114,6 +114,15 @@
obj.invokeMethodAsync(method, '', '', data.Os, data.Browser, data.Device, data.Language, data.Engine, data.UserAgent);
}
});
},
bb_vibrate: function () {
if ('vibrate' in window.navigator) {
window.navigator.vibrate([200, 100, 200]);
var handler = window.setTimeout(function () {
window.clearTimeout(handler);
window.navigator.vibrate([]);
}, 1000);
}
}
});

File diff suppressed because one or more lines are too long