From 2d52179e4d63626c65814787c71e9b27e1a311da Mon Sep 17 00:00:00 2001 From: kkxkx <63846879+kkxkx@users.noreply.github.com> Date: Thu, 23 Jul 2026 11:05:56 +0800 Subject: [PATCH 1/3] Update deviceId structure in camera configuration MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 修改了Camera组件在Edge浏览器不能切换多个摄像头画面的问题deviceId: { exact: deviceId },严格匹配模式 Signed-off-by: kkxkx <63846879+kkxkx@users.noreply.github.com> --- src/BootstrapBlazor/Components/Camera/Camera.razor.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/BootstrapBlazor/Components/Camera/Camera.razor.js b/src/BootstrapBlazor/Components/Camera/Camera.razor.js index 7a976fb8fd3..f1cc07dd70c 100644 --- a/src/BootstrapBlazor/Components/Camera/Camera.razor.js +++ b/src/BootstrapBlazor/Components/Camera/Camera.razor.js @@ -11,7 +11,7 @@ const openDevice = camera => { const videoHeight = parseInt(camera.el.getAttribute("data-video-height")) play(camera, { video: { - deviceId, + deviceId: { exact: deviceId }, width: { ideal: videoWidth }, height: { ideal: videoHeight } } From 42703224807033bd2294e0d254c6a258b7bdf5b9 Mon Sep 17 00:00:00 2001 From: Argo Zhang Date: Thu, 23 Jul 2026 11:54:15 +0800 Subject: [PATCH 2/3] chore: bump version 10.8.2-beta03 --- src/BootstrapBlazor/BootstrapBlazor.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/BootstrapBlazor/BootstrapBlazor.csproj b/src/BootstrapBlazor/BootstrapBlazor.csproj index 24dbadbd10b..c48947950e3 100644 --- a/src/BootstrapBlazor/BootstrapBlazor.csproj +++ b/src/BootstrapBlazor/BootstrapBlazor.csproj @@ -1,7 +1,7 @@  - 10.8.2-beta02 + 10.8.2-beta03 From d872ef765734dabf12c8c8b10efde86d44d77546 Mon Sep 17 00:00:00 2001 From: kkxkx <63846879+kkxkx@users.noreply.github.com> Date: Fri, 24 Jul 2026 10:36:06 +0800 Subject: [PATCH 3/3] Refactor camera functions for async handling MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 增加设备ID缓存,解决因严格模式ID改变 重启启停硬件导致UI闪屏问题 Signed-off-by: kkxkx <63846879+kkxkx@users.noreply.github.com> --- .../Components/Camera/Camera.razor.js | 61 ++++++++----------- 1 file changed, 27 insertions(+), 34 deletions(-) diff --git a/src/BootstrapBlazor/Components/Camera/Camera.razor.js b/src/BootstrapBlazor/Components/Camera/Camera.razor.js index f1cc07dd70c..f979b56ca28 100644 --- a/src/BootstrapBlazor/Components/Camera/Camera.razor.js +++ b/src/BootstrapBlazor/Components/Camera/Camera.razor.js @@ -1,4 +1,4 @@ -import Data from "../../modules/data.js" +import Data from "../../modules/data.js" const openDevice = camera => { if (camera.video) { @@ -29,42 +29,38 @@ const stopDevice = camera => { } } -const play = (camera, option = {}) => { +const play = async (camera, option = {}) => { const constrains = { - ...{ - video: { - facingMode: "environment" - }, - audio: false - }, + video: { facingMode: "environment" }, + audio: false, ...option } - navigator.mediaDevices.getUserMedia(constrains).then(stream => { + try { + const stream = await navigator.mediaDevices.getUserMedia(constrains); camera.video = { deviceId: option.video.deviceId }; camera.video.element = camera.el.querySelector('video') camera.video.element.srcObject = stream - camera.video.element.play() + await camera.video.element.play() camera.video.track = stream.getVideoTracks()[0] + // 写入当前正常运行的设备ID + camera.lastUsedDeviceId = option.video.deviceId.exact ?? option.video.deviceId; camera.invoke.invokeMethodAsync("TriggerOpen") - }).catch(err => { + } catch (err) { delete camera.video camera.invoke.invokeMethodAsync("TriggerError", err.name) - }) + } } export function init(id, invoke) { const el = document.getElementById(id) - if (el === null) { - return - } - const camera = { el, invoke } + if (el === null) return + // 新增lastUsedDeviceId记录当前正在运行的设备ID + const camera = { el, invoke, lastUsedDeviceId: null } Data.set(id, camera) navigator.mediaDevices.getUserMedia({ video: true, audio: false }).then(s => { navigator.mediaDevices.enumerateDevices().then(videoInputDevices => { - const videoInputs = videoInputDevices.filter(device => { - return device.kind === 'videoinput' - }) + const videoInputs = videoInputDevices.filter(device => device.kind === 'videoinput') invoke.invokeMethodAsync("TriggerInit", videoInputs) }) }).catch(err => { @@ -72,25 +68,22 @@ export function init(id, invoke) { }) } -export function update(id) { +export async function update(id) { const camera = Data.get(id) - if (camera === null) { - return - } + if (camera === null) return - // handler switch device + const domDeviceId = camera.el.getAttribute("data-device-id") + // ID没有发生变化,直接return,不会执行关闭、重开硬件流程,彻底消除闪烁 + if (camera.lastUsedDeviceId === domDeviceId) return; + + // 只有切换设备时才执行硬件重启 if (camera.video) { - const deviceId = camera.el.getAttribute("data-device-id") - if (camera.video.deviceId !== deviceId) { - stopDevice(camera) - openDevice(camera) - } - } - else { + stopDevice(camera) + await new Promise(r => setTimeout(r, 350)); + await openDevice(camera) + } else { const autoStart = camera.el.getAttribute("data-auto-start") || false - if (autoStart) { - openDevice(camera) - } + if (autoStart) await openDevice(camera) } }