electron perfect drag and drop : μια πιο κομψή υλοποίηση από το electron-drag

Ο υπεύθυνος προϊόντος ζήτησε η γραμμή εργαλείων κάτω από το παράθυρο electron να μπλοκάρει το δεξί κουμπί του ποντικιού.

Η εγγενής μεταφορά και απόθεση σε ηλεκτρόνιο κάτω από το παράθυρο ( app-region:drag) τρώει το συμβάν κλικ και δεν υπάρχει τρόπος να γίνει μπλοκάρισμα του δεξιού κλικ. Θα πρέπει να εφαρμόσετε το drag and drop χειροκίνητα.

Αν χρησιμοποιήσετε το συμβάν mousemove για την υλοποίηση της απαίτησης, όταν το ποντίκι μετακινείται γρήγορα, βγαίνει από την περιοχή του παραθύρου και το παράθυρο δεν ακολουθεί πλέον το ποντίκι.

Έχω υλοποιήσει αυτή την απαίτηση με βάση το συμβάν του δείκτη, χρησιμοποιώντας το setPointerCaptureΆνοιγμα σε νέο παράθυρο για τη σύλληψη της θέσης του ποντικιού εκτός του BrowserWindow, και λειτουργεί τέλεια.

Αυτή η λύση είναι καλύτερη από τη λύση electron-drag: έχει εξαρτώμενες από την πλατφόρμα δυαδικές εξαρτήσεις και μπορεί να είναι μπελάς η αναβάθμιση και η συσκευασία.

Διαπίστωσα ότι κανείς δεν έχει αναφερθεί ακόμη σε αυτή τη λύση στο διαδίκτυο, γι' αυτό την αναφέρω στο blog και την μοιράζομαι.

Οι διαφορές στον κώδικα μεταξύ των υλοποιήσεων παρατίθενται παρακάτω μόνο για λόγους αναφοράς. Ο βασικός κώδικας είναι web/src/lib/drag.coffee και main/ipc/drag.coffee.

web/src/lib/drag.coffee

import $on from '~/lib/on.coffee'
import ipc from '~/lib/ipc.coffee'
import platform from '@/config/platform.mjs'

{drag:{setBounds,getBounds}} = ipc
pointermove = 'pointermove'
IGNORE = new Set('SELECT BUTTON A INPUT TEXTAREA'.split ' ')
{round} = Math
export default main = (elem)=>
  if platform!='win32'
    return

  elem.style.appRegion = 'no-drag'

  moving = false

  init_w = init_h = init_x = init_y = init_top = init_left = undefined

  _move = (e)=>
    {screenX,screenY} = e
    setBounds(
      round screenX-init_x+init_left
      round screenY-init_y+init_top
      init_w
      init_h
    )
    return

  down = (e)=>
    if moving
      return
    if e.button!=0 # 鼠标左键
      return
    {target} = e
    p = e.target
    loop
      {nodeName} = p
      if IGNORE.has nodeName
        return
      if nodeName == 'BODY'
        break
      p = p.parentNode
    moving = true
    {screenX:init_x,screenY:init_y} = e

    elem.setPointerCapture e.pointerId
    elem.addEventListener pointermove,_move

    {
      x:init_left
      y:init_top
      height:init_h
      width:init_w
    } = await getBounds()

    console.log  await getBounds()
    return

  up = (e)=>
    if moving
      await _move(e)
      elem.releasePointerCapture e.pointerId
      elem.removeEventListener pointermove,_move
      moving = false
    return

  $on elem,{
    lostpointercapture:up
    pointercancel:up
    pointerdown:down
    pointerup:up
  }

  return

main/ipc/drag.coffee

export getBounds = ->
  @sender.getOwnerBrowserWindow().getBounds()

export setBounds = (x,y,width,height)->
  win = @sender.getOwnerBrowserWindow()
  # 不用 setPosition 是因为 https://github.com/electron/electron/issues/9477 browserWindow.setPosition(x,y) changed window size (windows/linux) with non default scaleLevel (125% for example)
  win.setBounds {
    x:Math.round(x)
    y:Math.round(y)
    width
    height
  }
  return

main/ipc.coffee

`export * as drag from './ipc/drag.coffee'`

web/src/page/recbar.vue

<template lang="pug">
-nav(:class="{ pause }")
nav(:class="{ pause }" ref="nav")
</template>
<script lang="coffee">
import drag from '~/lib/drag.coffee'
nav = shallowRef()
export default {
setup: =>
  onMounted =>
    drag(nav.value)
    return
  {
    nav
  }
}
</script>

main/boot.coffee

_handle = (k, v)=>
  if v instanceof Function
    ipcMain.handle k.join('.'), (e,args)=>
      v.apply(e,args)

  for [name,func] from Object.entries v
    _handle [...k, name], func

  return

for [k,v] from Object.entries ipc
  _handle([k], v)

web/src/lib/_on.coffee

export default (elem, dict)=>
  for event,func of dict
    elem.addEventListener(event, func)
  =>
    for event,func of dict
      elem.removeEventListener(event, func)

web/src/lib/on.coffee

import $on from './_on.coffee'
export default (elem, dict)=>
  unbind = $on elem, dict
  onUnmounted unbind
  unbind
Ενημερώσεις:
Από το: gcxfd