|
1 | 1 | <template> |
2 | 2 | <!-- 悬浮球 --> |
3 | | - <div class="weilin_prompt_ui_floating-ball" :style="ballStyle[i - 1]" |
4 | | - @mouseenter="handleMouseEnter(i - 1)" |
5 | | - @mouseleave="handleMouseLeave(i - 1)" |
6 | | - @mousedown="startDrag($event, i - 1)" |
7 | | - @mouseup="stopDrag($event, i - 1)" |
8 | | - v-for="i in savedFloatingBallCount" |
9 | | - :key="'floating-ball-' + i"> |
10 | | - <div class="weilin_prompt_ui_ball-content" @click="handleClick"> |
11 | | - <slot></slot> |
12 | | - </div> |
13 | | - <!-- 目录 --> |
14 | | - <div v-if="showMenu[i - 1]" class="weilin_prompt_ui_menu-container" @mousedown.stop> |
15 | | - <div class="weilin_prompt_ui_menu-item" @click="handleMenuItemClick('item1')">{{ t('floatingBall.promptBox') }}</div> |
16 | | - <div class="weilin_prompt_ui_menu-item" @click="handleMenuItemClick('item2')">{{ t('floatingBall.tagManager') }}</div> |
17 | | - <div class="weilin_prompt_ui_menu-item" @click="handleMenuItemClick('item3')">{{ t('floatingBall.loraManager') }}</div> |
18 | | - <div class="weilin_prompt_ui_menu-item" @click="handleMenuItemClick('item4')">{{ t('floatingBall.aiWindow') }}</div> |
19 | | - <div class="weilin_prompt_ui_menu-item" @click="handleMenuItemClick('item6')">{{ t('floatingBall.openNodeListWindow') }}</div> |
20 | | - <div class="weilin_prompt_ui_menu-item" @click="handleMenuItemClick('item7')">{{ t('floatingBall.tranToWeb') }}</div> |
21 | | - <div class="weilin_prompt_ui_menu-item" @click="handleMenuItemClick('item5')">{{ t('floatingBall.restoreWindow') }}</div> |
22 | | - </div> |
| 3 | + <div class="weilin_prompt_ui_floating-ball" :style="ballStyle[i - 1]" @mouseenter="handleMouseEnter(i - 1)" |
| 4 | + @mouseleave="handleMouseLeave(i - 1)" @mousedown="startDrag($event, i - 1)" @mouseup="stopDrag($event, i - 1)" |
| 5 | + v-for="i in savedFloatingBallCount" :key="'floating-ball-' + i"> |
| 6 | + <div class="weilin_prompt_ui_ball-content" @click="handleClick"> |
| 7 | + <slot></slot> |
| 8 | + </div> |
| 9 | + <!-- 目录 --> |
| 10 | + <div v-if="showMenu[i - 1]" class="weilin_prompt_ui_menu-container" @mousedown.stop> |
| 11 | + <div class="weilin_prompt_ui_menu-item" @click="handleMenuItemClick('item1')">{{ t('floatingBall.promptBox') |
| 12 | + }}</div> |
| 13 | + <div class="weilin_prompt_ui_menu-item" @click="handleMenuItemClick('item2')">{{ |
| 14 | + t('floatingBall.tagManager') }}</div> |
| 15 | + <div class="weilin_prompt_ui_menu-item" @click="handleMenuItemClick('item3')">{{ |
| 16 | + t('floatingBall.loraManager') }}</div> |
| 17 | + <div class="weilin_prompt_ui_menu-item" @click="handleMenuItemClick('item4')">{{ t('floatingBall.aiWindow') |
| 18 | + }}</div> |
| 19 | + <div class="weilin_prompt_ui_menu-item" @click="handleMenuItemClick('item6')">{{ |
| 20 | + t('floatingBall.openNodeListWindow') }}</div> |
| 21 | + <div class="weilin_prompt_ui_menu-item" @click="handleMenuItemClick('item7')">{{ t('floatingBall.tranToWeb') |
| 22 | + }}</div> |
| 23 | + <div class="weilin_prompt_ui_menu-item" @click="handleMenuItemClick('item5')">{{ |
| 24 | + t('floatingBall.restoreWindow') }}</div> |
| 25 | + </div> |
23 | 26 | </div> |
24 | 27 |
|
25 | 28 | <tranToWeb ref="tranToWebRef" /> |
@@ -59,43 +62,88 @@ const ballStyle = ref([]); |
59 | 62 | for (let i = 0; i < savedFloatingBallCount.value; i++) { |
60 | 63 | showMenu.value[i] = false; |
61 | 64 | isDragging.value[i] = false; |
| 65 | +
|
| 66 | + const viewportWidth = window.innerWidth; |
| 67 | + const viewportHeight = window.innerHeight; |
| 68 | + const ballSize = savedFloatingBallSize.value; |
| 69 | + const spacing = 10; // 球之间的间距 |
| 70 | +
|
| 71 | + // 计算每行能放多少个球 |
| 72 | + const ballsPerRow = Math.floor(viewportWidth / (ballSize + spacing)); |
| 73 | +
|
| 74 | + // 计算当前球的行和列 |
| 75 | + const row = Math.floor(i / ballsPerRow); |
| 76 | + const col = i % ballsPerRow; |
| 77 | +
|
| 78 | + // 计算初始位置 |
| 79 | + let x = 20 + col * (ballSize + spacing); |
| 80 | + let y = viewportHeight - 100 - row * (ballSize + spacing); |
| 81 | +
|
| 82 | + // 边界检查 |
| 83 | + x = Math.max(0, x); |
| 84 | + x = Math.min(x, viewportWidth - ballSize); |
| 85 | + y = Math.max(0, y); |
| 86 | + y = Math.min(y, viewportHeight - ballSize); |
| 87 | +
|
62 | 88 | ballPosition.value[i] = { |
63 | | - x: 20 + i * (savedFloatingBallSize.value + 10), // 增加间距 |
64 | | - y: window.innerHeight - 100, |
65 | | - width: savedFloatingBallSize.value + 'px', |
66 | | - height: savedFloatingBallSize.value + 'px' |
| 89 | + x: x, |
| 90 | + y: y, |
| 91 | + width: ballSize + 'px', |
| 92 | + height: ballSize + 'px' |
67 | 93 | }; |
68 | 94 | ballStyle.value[i] = { |
69 | 95 | left: `${ballPosition.value[i].x}px`, |
70 | 96 | top: `${ballPosition.value[i].y}px`, |
71 | | - width: `${savedFloatingBallSize.value}px`, |
72 | | - height: `${savedFloatingBallSize.value}px`, |
| 97 | + width: `${ballSize}px`, |
| 98 | + height: `${ballSize}px`, |
73 | 99 | } |
74 | 100 | } |
75 | 101 |
|
76 | 102 | // 开始拖拽 |
77 | 103 | const startDrag = (event, i) => { |
78 | | - // 判断点击是否在悬浮球本体或其直接子元素上 |
79 | | - const target = event.target; |
80 | | - if (target.closest('.weilin_prompt_ui_floating-ball')) { |
81 | | - isDragging.value[i] = true; |
82 | | - document.addEventListener('mousemove', (e) => onDrag(e, i)); |
83 | | - document.addEventListener('mouseup', (e) => stopDrag(e, i)); |
84 | | - } |
| 104 | + // 判断点击是否在悬浮球本体或其直接子元素上 |
| 105 | + const target = event.target; |
| 106 | + if (target.closest('.weilin_prompt_ui_floating-ball')) { |
| 107 | + isDragging.value[i] = true; |
| 108 | + document.addEventListener('mousemove', (e) => onDrag(e, i)); |
| 109 | + document.addEventListener('mouseup', (e) => stopDrag(e, i)); |
| 110 | + } |
85 | 111 | }; |
86 | 112 |
|
87 | 113 | // 拖拽中 |
88 | 114 | const onDrag = (event, i) => { |
89 | | - if (isDragging.value[i]) { |
90 | | - ballPosition.value[i].x = event.clientX - savedFloatingBallSize.value / 2; |
91 | | - ballPosition.value[i].y = event.clientY - savedFloatingBallSize.value / 2; |
92 | | - ballStyle.value[i] = { |
93 | | - left: `${ballPosition.value[i].x}px`, |
94 | | - top: `${ballPosition.value[i].y}px`, |
95 | | - width: `${savedFloatingBallSize.value}px`, |
96 | | - height: `${savedFloatingBallSize.value}px`, |
97 | | - }; |
98 | | - } |
| 115 | + if (isDragging.value[i]) { |
| 116 | + const viewportWidth = window.innerWidth; |
| 117 | + const viewportHeight = window.innerHeight; |
| 118 | + const ballSize = savedFloatingBallSize.value; |
| 119 | +
|
| 120 | + // 计算新位置并确保不超出边界 |
| 121 | + let newX = event.clientX - ballSize / 2; |
| 122 | + let newY = event.clientY - ballSize / 2; |
| 123 | +
|
| 124 | + // 确保左侧不超出边界 |
| 125 | + newX = Math.max(0, newX); |
| 126 | + // 确保右侧不超出边界 |
| 127 | + newX = Math.min(newX, viewportWidth - ballSize); |
| 128 | + // 确保顶部不超出边界 |
| 129 | + newY = Math.max(0, newY); |
| 130 | + // 确保底部不超出边界 |
| 131 | + newY = Math.min(newY, viewportHeight - ballSize); |
| 132 | +
|
| 133 | + ballPosition.value[i] = { |
| 134 | + x: newX, |
| 135 | + y: newY, |
| 136 | + width: ballSize + 'px', |
| 137 | + height: ballSize + 'px' |
| 138 | + }; |
| 139 | +
|
| 140 | + ballStyle.value[i] = { |
| 141 | + left: `${ballPosition.value[i].x}px`, |
| 142 | + top: `${ballPosition.value[i].y}px`, |
| 143 | + width: `${ballSize}px`, |
| 144 | + height: `${ballSize}px`, |
| 145 | + }; |
| 146 | + } |
99 | 147 | }; |
100 | 148 |
|
101 | 149 | // 停止拖拽 |
@@ -163,17 +211,40 @@ const handleMessage = (event) => { |
163 | 211 | for (let i = 0; i < savedFloatingBallCount.value; i++) { |
164 | 212 | showMenu.value[i] = false; |
165 | 213 | isDragging.value[i] = false; |
| 214 | +
|
| 215 | + const viewportWidth = window.innerWidth; |
| 216 | + const viewportHeight = window.innerHeight; |
| 217 | + const ballSize = savedFloatingBallSize.value; |
| 218 | + const spacing = 10; // 球之间的间距 |
| 219 | +
|
| 220 | + // 计算每行能放多少个球 |
| 221 | + const ballsPerRow = Math.floor(viewportWidth / (ballSize + spacing)); |
| 222 | +
|
| 223 | + // 计算当前球的行和列 |
| 224 | + const row = Math.floor(i / ballsPerRow); |
| 225 | + const col = i % ballsPerRow; |
| 226 | +
|
| 227 | + // 计算初始位置 |
| 228 | + let x = 20 + col * (ballSize + spacing); |
| 229 | + let y = viewportHeight - 100 - row * (ballSize + spacing); |
| 230 | +
|
| 231 | + // 边界检查 |
| 232 | + x = Math.max(0, x); |
| 233 | + x = Math.min(x, viewportWidth - ballSize); |
| 234 | + y = Math.max(0, y); |
| 235 | + y = Math.min(y, viewportHeight - ballSize); |
| 236 | +
|
166 | 237 | ballPosition.value[i] = { |
167 | | - x: 20 + i * (savedFloatingBallSize.value + 10), |
168 | | - y: window.innerHeight - 100, |
169 | | - width: savedFloatingBallSize.value + 'px', |
170 | | - height: savedFloatingBallSize.value + 'px' |
| 238 | + x: x, |
| 239 | + y: y, |
| 240 | + width: ballSize + 'px', |
| 241 | + height: ballSize + 'px' |
171 | 242 | }; |
172 | 243 | ballStyle.value[i] = { |
173 | 244 | left: `${ballPosition.value[i].x}px`, |
174 | 245 | top: `${ballPosition.value[i].y}px`, |
175 | | - width: `${savedFloatingBallSize.value}px`, |
176 | | - height: `${savedFloatingBallSize.value}px`, |
| 246 | + width: `${ballSize}px`, |
| 247 | + height: `${ballSize}px`, |
177 | 248 | } |
178 | 249 | } |
179 | 250 | } |
|
0 commit comments