fix(im): 清理 RTC 媒体元素卸载时的 srcObject
- 对齐 Vue3 管理后台 63dfc5e 的 RTC 媒体元素处理 - useMediaStreamElement 改为 callback ref 闭包保存当前元素 - 组件卸载或 ref 置空时清理旧 video/audio 元素的 srcObject,避免流关闭后画面残留 - 同步适配 web-antd、web-ele、web-antdv-next 验证: - pnpm -F @vben/web-antd run typecheck - pnpm -F @vben/web-ele run typecheck - web-antdv-next 仍为既有 55 个类型错误,无 RTC 新增错误migration
parent
953e7c1502
commit
0a76bed471
|
|
@ -1,4 +1,4 @@
|
||||||
import { ref, type VNodeRef, watch } from 'vue'
|
import { type VNodeRef, watch } from 'vue'
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 把响应式 MediaStream 挂到 `<video>` / `<audio>` 元素的 srcObject 上;
|
* 把响应式 MediaStream 挂到 `<video>` / `<audio>` 元素的 srcObject 上;
|
||||||
|
|
@ -7,21 +7,34 @@ import { ref, type VNodeRef, watch } from 'vue'
|
||||||
export function useMediaStreamElement<T extends HTMLMediaElement>(
|
export function useMediaStreamElement<T extends HTMLMediaElement>(
|
||||||
streamSource: () => MediaStream | null | undefined
|
streamSource: () => MediaStream | null | undefined
|
||||||
): VNodeRef {
|
): VNodeRef {
|
||||||
const elRef = ref<T>()
|
let el: T | null = null
|
||||||
const syncStream = (stream = streamSource()) => {
|
let currentStream: MediaStream | null | undefined
|
||||||
if (elRef.value) {
|
|
||||||
elRef.value.srcObject = stream || null
|
const syncStream = () => {
|
||||||
|
if (el) {
|
||||||
|
el.srcObject = currentStream || null
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
watch(
|
watch(
|
||||||
streamSource,
|
streamSource,
|
||||||
(stream) => {
|
(stream) => {
|
||||||
syncStream(stream)
|
currentStream = stream
|
||||||
|
syncStream()
|
||||||
},
|
},
|
||||||
{ flush: 'post', immediate: true }
|
{ flush: 'post', immediate: true }
|
||||||
)
|
)
|
||||||
return (el) => {
|
|
||||||
elRef.value = el instanceof HTMLMediaElement ? (el as T) : undefined
|
return (value) => {
|
||||||
syncStream()
|
if (value instanceof HTMLMediaElement) {
|
||||||
|
el = value as T
|
||||||
|
syncStream()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if (el) {
|
||||||
|
el.srcObject = null
|
||||||
|
}
|
||||||
|
el = null
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
import { ref, type VNodeRef, watch } from 'vue'
|
import { type VNodeRef, watch } from 'vue'
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 把响应式 MediaStream 挂到 `<video>` / `<audio>` 元素的 srcObject 上;
|
* 把响应式 MediaStream 挂到 `<video>` / `<audio>` 元素的 srcObject 上;
|
||||||
|
|
@ -7,21 +7,34 @@ import { ref, type VNodeRef, watch } from 'vue'
|
||||||
export function useMediaStreamElement<T extends HTMLMediaElement>(
|
export function useMediaStreamElement<T extends HTMLMediaElement>(
|
||||||
streamSource: () => MediaStream | null | undefined
|
streamSource: () => MediaStream | null | undefined
|
||||||
): VNodeRef {
|
): VNodeRef {
|
||||||
const elRef = ref<T>()
|
let el: T | null = null
|
||||||
const syncStream = (stream = streamSource()) => {
|
let currentStream: MediaStream | null | undefined
|
||||||
if (elRef.value) {
|
|
||||||
elRef.value.srcObject = stream || null
|
const syncStream = () => {
|
||||||
|
if (el) {
|
||||||
|
el.srcObject = currentStream || null
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
watch(
|
watch(
|
||||||
streamSource,
|
streamSource,
|
||||||
(stream) => {
|
(stream) => {
|
||||||
syncStream(stream)
|
currentStream = stream
|
||||||
|
syncStream()
|
||||||
},
|
},
|
||||||
{ flush: 'post', immediate: true }
|
{ flush: 'post', immediate: true }
|
||||||
)
|
)
|
||||||
return (el) => {
|
|
||||||
elRef.value = el instanceof HTMLMediaElement ? (el as T) : undefined
|
return (value) => {
|
||||||
syncStream()
|
if (value instanceof HTMLMediaElement) {
|
||||||
|
el = value as T
|
||||||
|
syncStream()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if (el) {
|
||||||
|
el.srcObject = null
|
||||||
|
}
|
||||||
|
el = null
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
import { ref, type VNodeRef, watch } from 'vue'
|
import { type VNodeRef, watch } from 'vue'
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 把响应式 MediaStream 挂到 `<video>` / `<audio>` 元素的 srcObject 上;
|
* 把响应式 MediaStream 挂到 `<video>` / `<audio>` 元素的 srcObject 上;
|
||||||
|
|
@ -7,21 +7,34 @@ import { ref, type VNodeRef, watch } from 'vue'
|
||||||
export function useMediaStreamElement<T extends HTMLMediaElement>(
|
export function useMediaStreamElement<T extends HTMLMediaElement>(
|
||||||
streamSource: () => MediaStream | null | undefined
|
streamSource: () => MediaStream | null | undefined
|
||||||
): VNodeRef {
|
): VNodeRef {
|
||||||
const elRef = ref<T>()
|
let el: T | null = null
|
||||||
const syncStream = (stream = streamSource()) => {
|
let currentStream: MediaStream | null | undefined
|
||||||
if (elRef.value) {
|
|
||||||
elRef.value.srcObject = stream || null
|
const syncStream = () => {
|
||||||
|
if (el) {
|
||||||
|
el.srcObject = currentStream || null
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
watch(
|
watch(
|
||||||
streamSource,
|
streamSource,
|
||||||
(stream) => {
|
(stream) => {
|
||||||
syncStream(stream)
|
currentStream = stream
|
||||||
|
syncStream()
|
||||||
},
|
},
|
||||||
{ flush: 'post', immediate: true }
|
{ flush: 'post', immediate: true }
|
||||||
)
|
)
|
||||||
return (el) => {
|
|
||||||
elRef.value = el instanceof HTMLMediaElement ? (el as T) : undefined
|
return (value) => {
|
||||||
syncStream()
|
if (value instanceof HTMLMediaElement) {
|
||||||
|
el = value as T
|
||||||
|
syncStream()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if (el) {
|
||||||
|
el.srcObject = null
|
||||||
|
}
|
||||||
|
el = null
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue