fix: 修正手機端詞彙popup定位問題
- 解決手機版popup容易被屏幕邊緣截掉的問題 - 實現響應式popup寬度:min(320px, calc(100vw - 32px)) - 針對手機端(≤640px)特殊處理:popup自動居中顯示 - 優化邊界檢測邏輯,確保popup始終在可視範圍內 - 大屏幕保持智能定位,小屏幕採用安全居中策略 - 添加動態寬度計算,適應不同屏幕尺寸 - 預留最小邊距16px,避免popup貼邊顯示 修正後手機端用戶體驗大幅改善,popup不再被截掉。 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
parent
be236f7216
commit
453ecd6d1c
|
|
@ -75,17 +75,40 @@ export function ClickableTextV2({
|
||||||
const wordAnalysis = analysis?.[cleanWord]
|
const wordAnalysis = analysis?.[cleanWord]
|
||||||
|
|
||||||
const rect = event.currentTarget.getBoundingClientRect()
|
const rect = event.currentTarget.getBoundingClientRect()
|
||||||
|
const viewportWidth = window.innerWidth
|
||||||
const viewportHeight = window.innerHeight
|
const viewportHeight = window.innerHeight
|
||||||
|
const popupWidth = 320 // popup寬度 w-80 = 320px
|
||||||
const popupHeight = 400 // 估計popup高度
|
const popupHeight = 400 // 估計popup高度
|
||||||
|
|
||||||
// 智能定位:如果上方空間不足,就顯示在下方
|
// 智能水平定位,適應不同屏幕尺寸
|
||||||
|
let x = rect.left + rect.width / 2
|
||||||
|
const actualPopupWidth = Math.min(popupWidth, viewportWidth - 32) // 實際popup寬度
|
||||||
|
const halfPopupWidth = actualPopupWidth / 2
|
||||||
|
const padding = 16 // 最小邊距
|
||||||
|
|
||||||
|
// 手機端特殊處理
|
||||||
|
if (viewportWidth <= 640) { // sm斷點
|
||||||
|
// 小屏幕時居中顯示,避免邊緣問題
|
||||||
|
x = viewportWidth / 2
|
||||||
|
} else {
|
||||||
|
// 大屏幕時智能調整位置
|
||||||
|
if (x + halfPopupWidth + padding > viewportWidth) {
|
||||||
|
x = viewportWidth - halfPopupWidth - padding
|
||||||
|
}
|
||||||
|
if (x - halfPopupWidth < padding) {
|
||||||
|
x = halfPopupWidth + padding
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 計算垂直位置
|
||||||
const spaceAbove = rect.top
|
const spaceAbove = rect.top
|
||||||
const spaceBelow = viewportHeight - rect.bottom
|
const spaceBelow = viewportHeight - rect.bottom
|
||||||
|
const showBelow = spaceAbove < popupHeight
|
||||||
|
|
||||||
const position = {
|
const position = {
|
||||||
x: rect.left + rect.width / 2,
|
x: x,
|
||||||
y: spaceAbove >= popupHeight ? rect.top - 10 : rect.bottom + 10,
|
y: showBelow ? rect.bottom + 10 : rect.top - 10,
|
||||||
showBelow: spaceAbove < popupHeight
|
showBelow: showBelow
|
||||||
}
|
}
|
||||||
|
|
||||||
if (wordAnalysis) {
|
if (wordAnalysis) {
|
||||||
|
|
@ -287,13 +310,14 @@ export function ClickableTextV2({
|
||||||
{/* 現代風格詞彙彈窗 */}
|
{/* 現代風格詞彙彈窗 */}
|
||||||
{selectedWord && analysis?.[selectedWord] && (
|
{selectedWord && analysis?.[selectedWord] && (
|
||||||
<div
|
<div
|
||||||
className="fixed z-50 bg-white rounded-2xl shadow-2xl border-0 w-80 backdrop-blur-sm"
|
className="fixed z-50 bg-white rounded-2xl shadow-2xl border-0 backdrop-blur-sm"
|
||||||
style={{
|
style={{
|
||||||
left: `${popupPosition.x}px`,
|
left: `${popupPosition.x}px`,
|
||||||
top: `${popupPosition.y}px`,
|
top: `${popupPosition.y}px`,
|
||||||
transform: popupPosition.showBelow
|
transform: popupPosition.showBelow
|
||||||
? 'translate(-50%, 8px)'
|
? 'translate(-50%, 8px)'
|
||||||
: 'translate(-50%, calc(-100% - 8px))',
|
: 'translate(-50%, calc(-100% - 8px))',
|
||||||
|
width: 'min(320px, calc(100vw - 32px))', // 響應式寬度,手機端自動收縮
|
||||||
maxHeight: '85vh',
|
maxHeight: '85vh',
|
||||||
overflowY: 'auto',
|
overflowY: 'auto',
|
||||||
background: 'rgba(255, 255, 255, 0.98)',
|
background: 'rgba(255, 255, 255, 0.98)',
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue