修复桌面端拖动悬浮通话窗口后收窄浏览器至移动端断点,通话条卡在旧桌面坐标不跟随移动端布局
现象:视频通话最小化后处于桌面宽度(>640px)时,拖动悬浮小窗到任意位置(dragStart 会把
定位方式从 CSS 的 right/auto-left 切换成显式 left/top 内联样式,方便拖拽期间自由移动),
之后把浏览器窗口收窄到 640px 以下(真实场景:桌面用户把窗口拖窄到半屏和另一个应用并排),
悬浮条不会像预期那样贴顶变成通栏胶囊(base.css 里
#video-container.minimized:not(.audio-minimized) 的移动端规则:left:0/right:auto/
top:var(--caption-panel-height)/width:100%/height:11rem),而是继续停在拖拽结束时的旧
桌面坐标——因为内联 style 的优先级恒高于任何样式表选择器,不管后者的媒体查询是否匹配,
移动端规则里的 left/right/top 全部被内联值盖住,只有从未被内联样式接触过的 width/height
还能生效,导致宽/高不成比例、位置错位。
修复:CallPanel 新增 handleWindowResize,监听 window resize;每次触发时如果
matchMedia('(width<=640px)') 命中且当前处于 minimized,就清掉 containerRef 上手动写入的
left/right/top 内联样式,把定位权交还给样式表,让移动端规则完整生效。componentDidMount/
componentWillUnmount 里和已有的 pointerdown/move/up 监听一起注册/清理。从未拖拽过时这个
清理是空操作,不影响现有行为。
验证:真实 CallPanel 实例(React Fiber 直接获取),伪造 canvas/AudioContext 媒体流跑通整
个通话中状态,用 computer 工具做真实指针拖拽把悬浮窗从默认右上角拖到别处(确认
style.left/top 已写入、right:auto),再用 resize_window 把视口收窄到 375px 宽并确认应用
自身的 resize 监听正确触发(displayMobile 状态同步更新)——收窄后 style 只剩
"cursor: grab",left/right/top 均被清空,getComputedStyle 显示 left:0/top:53.33px(=
var(--caption-panel-height)按当前根字号换算)/width:375px(100%)/height:146.66px(11rem),
与移动端样式表规则完全一致;再放宽回桌面宽度确认悬浮窗正常回到默认右上角18rem方框位置,
未引入回归。
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Sonnet 5
parent
0748f30cc1
commit
a6014b84ee
@@ -175,6 +175,23 @@ class CallPanel extends React.PureComponent {
|
||||
this.containerRef.current.style.cursor = 'grab';
|
||||
}
|
||||
};
|
||||
// dragStart's inline left/top/right (set the first time the minimized bubble is dragged, see
|
||||
// above) always win over base.css's #video-container.minimized:not(.audio-minimized) mobile
|
||||
// rule -- inline style beats any stylesheet selector regardless of media query. A desktop user
|
||||
// who drags the bubble somewhere and then narrows the window below 640px (a real everyday
|
||||
// action -- snapping the browser to half the screen, say) would otherwise be stuck with the
|
||||
// bubble pinned at its old desktop-width position/size instead of docking as the intended
|
||||
// mobile full-width strip. Clearing the manual offsets once the mobile breakpoint applies lets
|
||||
// the stylesheet rule take back over; harmless (a no-op) whenever nothing was ever dragged.
|
||||
this.handleWindowResize = () => {
|
||||
if (this.props.minimized && this.containerRef && this.containerRef.current &&
|
||||
window.matchMedia('(width<=640px)').matches) {
|
||||
const el = this.containerRef.current;
|
||||
el.style.removeProperty('left');
|
||||
el.style.removeProperty('right');
|
||||
el.style.removeProperty('top');
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
@@ -191,6 +208,7 @@ class CallPanel extends React.PureComponent {
|
||||
this.containerRef.current.addEventListener('pointermove', this.drag);
|
||||
this.containerRef.current.addEventListener('pointerup', this.dragEnd);
|
||||
}
|
||||
window.addEventListener('resize', this.handleWindowResize);
|
||||
}
|
||||
|
||||
componentWillUnmount() {
|
||||
@@ -199,6 +217,7 @@ class CallPanel extends React.PureComponent {
|
||||
topic.onInfo = this.previousOnInfo;
|
||||
this.stop();
|
||||
|
||||
window.removeEventListener('resize', this.handleWindowResize);
|
||||
if (this.containerRef) {
|
||||
this.containerRef.current.removeEventListener('pointerdown', this.dragStart);
|
||||
this.containerRef.current.removeEventListener('pointermove', this.drag);
|
||||
|
||||
Reference in New Issue
Block a user