@@ -219,7 +219,7 @@ export default GameEmbed;
219219function registerGameButton ( ) {
220220 // 在 windows 注入游戏按钮样式
221221 const style = document . createElement ( 'style' ) ;
222- const rootSelector = `a[href*="${ scriptSrc . hostname } /#/"]`
222+ const rootSelector = `a[href*="${ scriptSrc . hostname } /#/"]` ;
223223 style . innerHTML = `
224224 ${ rootSelector } , ${ rootSelector } >span>span {
225225 display: inline-flex;
@@ -269,6 +269,55 @@ function registerGameButton() {
269269 align-items: center;
270270 justify-content: center;
271271 }
272+ .game-embed-iframe {
273+ width: 100%;
274+ height: 100%;
275+ border: none;
276+ border-radius: 8px;
277+ }
278+ .game-embed-container {
279+ position: fixed;
280+ background-color: rgba(0, 0, 0, 0.5);
281+ z-index: 1001;
282+ display: flex;
283+ flex-direction: column;
284+ align-items: center;
285+ justify-content: center;
286+ resize: both;
287+ overflow: hidden;
288+ border-radius: 8px;
289+ box-shadow: 0 4px 12px rgba(0, 0, 0, 0.3);
290+ min-width: 100px;
291+ min-height: 100px;
292+ }
293+ .game-embed-close-button {
294+ background: transparent;
295+ border: none;
296+ color: white;
297+ font-size: 24px;
298+ cursor: pointer;
299+ z-index: 1005;
300+ }
301+ .game-embed-drag-handle {
302+ position: relative;
303+ width: 100%;
304+ height: 30px;
305+ cursor: grab;
306+ background-color: rgba(0, 0, 0, 0.1);
307+ border-top-left-radius: 8px;
308+ border-top-right-radius: 8px;
309+ z-index: 1002;
310+ text-align: right;
311+ user-select: none;
312+ }
313+ .game-embed-open-button {
314+ background: transparent;
315+ border: none;
316+ color: white;
317+ font-size: 18px;
318+ cursor: pointer;
319+ z-index: 1003;
320+ }
272321 ` ;
273322 document . head . appendChild ( style ) ;
274323
@@ -300,120 +349,135 @@ interface IRect {
300349 height : number ;
301350}
302351
303- // 创建一个浮动的可调整窗口大小的 iframe 来加载游戏房间, 默认大小为 800x600
352+ // 创建一个浮动的可调整窗口大小的 iframe 来加载游戏房间, 默认大小为 300 x 400
304353function appendGameViewIframe ( roomUrl : string ) {
354+ const minWidth = 100 ;
355+ const minHeight = 100 ;
305356 let iframe = document . getElementById ( 'game-view-iframe' ) as HTMLIFrameElement | null ;
306357 let rect : IRect | null = JSON . parse ( localStorage . getItem ( 'game-view-iframe-rect' ) || 'null' ) ;
307358
359+ // 辅助函数:保存当前位置和尺寸到localStorage
360+ const saveRect = ( container : HTMLElement ) => {
361+ const currentRect : IRect = {
362+ top : parseFloat ( container . style . top . replace ( 'px' , '' ) ) || 0 ,
363+ left : parseFloat ( container . style . left . replace ( 'px' , '' ) ) || 0 ,
364+ width : Math . max ( container . offsetWidth , minWidth ) ,
365+ height : Math . max ( container . offsetHeight , minHeight )
366+ } ;
367+ localStorage . setItem ( 'game-view-iframe-rect' , JSON . stringify ( currentRect ) ) ;
368+ } ;
369+
370+ // 辅助函数:应用边界检查
371+ const applyBounds = ( container : HTMLElement ) => {
372+ const rect = container . getBoundingClientRect ( ) ;
373+ const maxX = window . innerWidth - rect . width ;
374+ const maxY = window . innerHeight - rect . height ;
375+ const newLeft = Math . max ( 0 , Math . min ( parseFloat ( container . style . left . replace ( 'px' , '' ) ) , maxX ) ) ;
376+ const newTop = Math . max ( 0 , Math . min ( parseFloat ( container . style . top . replace ( 'px' , '' ) ) , maxY ) ) ;
377+ container . style . left = newLeft + 'px' ;
378+ container . style . top = newTop + 'px' ;
379+ } ;
380+
308381 if ( ! iframe ) {
309382 iframe = document . createElement ( 'iframe' ) ;
310383 iframe . id = 'game-view-iframe' ;
311- iframe . style . width = '100%' ;
312- iframe . style . height = '100%' ;
313- iframe . style . border = 'none' ;
314- iframe . style . borderRadius = '8px' ;
384+ iframe . className = 'game-embed-iframe' ;
315385 iframe . src = roomUrl ;
316386
317387 const container = document . createElement ( 'div' ) ;
318388 container . id = 'game-view-container' ;
319- container . style . position = 'fixed' ;
320- container . style . top = ( rect ?. top ?? ( window . innerHeight - 320 ) / 2 ) + 'px' ;
389+ container . className = 'game-embed-container' ;
390+ // 保留动态样式(位置和尺寸)
391+ container . style . top = ( rect ?. top ?? ( window . innerHeight - 320 ) / 2 ) + 'px' ;
321392 container . style . left = ( rect ?. left ?? ( window . innerWidth - 420 ) / 2 ) + 'px' ;
322- container . style . width = ( rect ?. width || 300 ) + 'px' ;
323- container . style . height = ( rect ?. height || 400 ) + 'px' ;
324- container . style . backgroundColor = 'rgba(0, 0, 0, 0.5)' ;
325- container . style . zIndex = '1001' ;
326- container . style . display = 'flex' ;
327- container . style . flexDirection = 'column' ;
328- container . style . alignItems = 'center' ;
329- container . style . justifyContent = 'center' ;
330- container . style . resize = 'both' ;
331- container . style . overflow = 'hidden' ;
332- container . style . borderRadius = '8px' ;
333- container . style . boxShadow = '0 4px 12px rgba(0, 0, 0, 0.3)' ;
393+ container . style . width = Math . max ( rect ?. width || 300 , minWidth ) + 'px' ;
394+ container . style . height = Math . max ( rect ?. height || 400 , minHeight ) + 'px' ;
334395
335396 // 关闭按钮
336397 const closeButton = document . createElement ( 'button' ) ;
398+ closeButton . className = 'game-embed-close-button' ;
337399 closeButton . innerText = '×' ;
338- closeButton . style . background = 'transparent' ;
339- closeButton . style . border = 'none' ;
340- closeButton . style . color = 'white' ;
341- closeButton . style . fontSize = '24px' ;
342- closeButton . style . cursor = 'pointer' ;
343- closeButton . style . zIndex = '1005' ;
344400 closeButton . addEventListener ( 'click' , ( ) => {
345- document . body . removeChild ( container ) ;
346- localStorage . setItem ( 'game-view-iframe-rect' , JSON . stringify ( {
347- top : Number ( container . style . top . replace ( 'px' , '' ) ) ,
348- left : Number ( container . style . left . replace ( 'px' , '' ) ) ,
349- width : container . offsetWidth ,
350- height : container . offsetHeight
351- } ) ) ;
401+ if ( document . body . contains ( container ) ) {
402+ document . body . removeChild ( container ) ;
403+ saveRect ( container ) ;
404+ }
352405 } ) ;
353406
354407 // 拖拽控制标签
355408 const dragHandle = document . createElement ( 'div' ) ;
356- dragHandle . style . position = 'relative' ;
357- dragHandle . style . width = '100%' ;
358- dragHandle . style . height = '30px' ;
359- dragHandle . style . cursor = 'grab' ;
360- dragHandle . style . backgroundColor = 'rgba(0, 0, 0, 0.1)' ;
361- dragHandle . style . borderTopLeftRadius = '8px' ;
362- dragHandle . style . borderTopRightRadius = '8px' ;
363- dragHandle . style . zIndex = '1002' ;
364- dragHandle . style . textAlign = 'right' ;
365- dragHandle . style . userSelect = 'none' ;
409+ dragHandle . className = 'game-embed-drag-handle' ;
366410 container . appendChild ( dragHandle ) ;
367411
368412 // 打开新窗口按钮
369- const openButton = document . createElement ( 'button' ) ;
413+ const openButton = document . createElement ( 'button' ) ;
414+ openButton . className = 'game-embed-open-button' ;
370415 openButton . innerText = '↗' ;
371- openButton . style . background = 'transparent' ;
372- openButton . style . border = 'none' ;
373- openButton . style . color = 'white' ;
374- openButton . style . fontSize = '18px' ;
375- openButton . style . cursor = 'pointer' ;
376- openButton . style . zIndex = '1003' ;
377416 openButton . title = '在新窗口打开游戏' ;
378417 openButton . addEventListener ( 'click' , ( ) => {
379418 window . open ( roomUrl . replace ( / \/ l \/ / , '/r/' ) , '_blank' ) ;
380419 } ) ;
381420 dragHandle . appendChild ( openButton ) ;
382421 dragHandle . appendChild ( closeButton ) ;
383422
384- // 允许拖动窗口
423+ // 拖动状态变量
385424 let isDragging = false ;
386425 let dragOffsetX = 0 ;
387426 let dragOffsetY = 0 ;
388427
389- dragHandle . addEventListener ( 'mousedown' , ( e ) => {
390- if ( e . target === closeButton ) return ; // 不允许拖动关闭按钮
428+ // 鼠标拖动事件(桌面端)
429+ const startDrag = ( clientX : number , clientY : number ) => {
391430 isDragging = true ;
392- dragOffsetX = e . clientX - container . offsetLeft ;
393- dragOffsetY = e . clientY - container . offsetTop ;
431+ dragOffsetX = clientX - container . offsetLeft ;
432+ dragOffsetY = clientY - container . offsetTop ;
394433 container . style . cursor = 'grabbing' ;
395- } ) ;
434+ } ;
396435
397- document . addEventListener ( 'mousemove' , ( e ) => {
436+ const doDrag = ( clientX : number , clientY : number ) => {
398437 if ( isDragging ) {
399- container . style . left = ( e . clientX - dragOffsetX ) + 'px' ;
400- container . style . top = ( e . clientY - dragOffsetY ) + 'px' ;
438+ container . style . left = ( clientX - dragOffsetX ) + 'px' ;
439+ container . style . top = ( clientY - dragOffsetY ) + 'px' ;
401440 }
402- } ) ;
441+ } ;
403442
404- document . addEventListener ( 'mouseup' , ( ) => {
443+ const endDrag = ( ) => {
405444 if ( isDragging ) {
406445 isDragging = false ;
407446 container . style . cursor = 'default' ;
408- localStorage . setItem ( 'game-view-iframe-rect' , JSON . stringify ( {
409- top : Number ( container . style . top . replace ( 'px' , '' ) ) ,
410- left : Number ( container . style . left . replace ( 'px' , '' ) ) ,
411- width : container . offsetWidth ,
412- height : container . offsetHeight
413- } ) ) ;
447+ applyBounds ( container ) ;
448+ saveRect ( container ) ;
414449 }
450+ } ;
451+
452+ // 鼠标事件
453+ dragHandle . addEventListener ( 'mousedown' , ( e ) => {
454+ if ( e . target === closeButton ) return ;
455+ startDrag ( e . clientX , e . clientY ) ;
456+ } ) ;
457+
458+ document . addEventListener ( 'mousemove' , ( e ) => {
459+ doDrag ( e . clientX , e . clientY ) ;
415460 } ) ;
416461
462+ document . addEventListener ( 'mouseup' , endDrag ) ;
463+
464+ // 触摸事件(移动端支持)
465+ dragHandle . addEventListener ( 'touchstart' , ( e ) => {
466+ if ( e . target === closeButton ) return ;
467+ const touch = e . touches [ 0 ] ;
468+ startDrag ( touch . clientX , touch . clientY ) ;
469+ } , { passive : false } ) ;
470+
471+ document . addEventListener ( 'touchmove' , ( e ) => {
472+ if ( isDragging ) {
473+ e . preventDefault ( ) ; // 防止页面滚动
474+ const touch = e . touches [ 0 ] ;
475+ doDrag ( touch . clientX , touch . clientY ) ;
476+ }
477+ } , { passive : false } ) ;
478+
479+ document . addEventListener ( 'touchend' , endDrag ) ;
480+
417481 container . appendChild ( iframe ) ;
418482 document . body . appendChild ( container ) ;
419483 }
0 commit comments