( FeriX | 2023. 12. 19., k – 18:40 )

Azért persze szépen egyszerűen le lehet írni, hogy klikkelni szeretnék és sztringből függvényt hívni paraméterekkel, az nem is olyan bonyolult. De mielőtt JavaScript felé fordulsz, van néhány dolog amin nem lehet átlépni, főleg ha Te szeretnél mindent megírni.

Nekem a C# nyelv áll legközelebb a szívhez, ezért a JavaScript/TypeScript amit írni szoktam eléggé hasonlít rá. A szememnek kényelmes, ha ránézek a kódra, és egyforma a struktúra. Ezért amit itt látni fogsz, az ezért olyan amilyen.

A click esemény önmagában mondhatni elavult, és el kell felejteni. Sokkal többről van szó mint a click. Alapból ott van az egér, a ceruza és az ujjbegy. Napi szinten beépült az emberek életébe, és bármit is csinálsz, mindenki a berögzült mozdulataival fog interakcióba lépni a kijelzővel. Ezért alkották meg a Pointer Events API-t. (https://developer.mozilla.org/en-US/docs/Web/API/Pointer_events) Minden bemenetet támogat egyszerre, ha felhasználó eszköze elég modern hogy a frissítések minden OS-en meglegyenek. Viszont vannak régebbi mobilok, amik frissítés nélkül maradtak bármilyen okból is, ezért szükséges még a Touch Events API használata. (https://developer.mozilla.org/en-US/docs/Web/API/Touch_events) Így garantált hogy minden eszközön működni fog.

Ha mindent Te szeretnél megírni, akkor szükséged lesz egy kiinduló pontra, hogy kezeld ezeket az interakciókat. Nem írtam kommentet, helyette próbáltam úgy fogalmazni a kódban, hogy ha végig olvasod akkor érthető legyen. Rakd bele a scripteket egy "Szkriptem.js" fájlba, vagy nevezd ahogy szeretnéd, csak a html-ben is módosítsd.

Ez a két osztály kezeli a pointer* és touch* eseményeket egy klikkhez. De úgy van megírva, hogy bővíthesd több ujjas interakciókhoz.

/* eslint-disable no-console */

class Négyszög {
  constructor() {
    this.kezdőX = 0
    this.kezdőY = 0
    this.végX = 0
    this.végY = 0
  }

  kezdőPont(x, y) {
    this.kezdőX = x
    this.kezdőY = y
  }

  végPont(x, y) {
    this.végX = x
    this.végY = y
  }
}

class MutatóVagyUjjbegy {
  constructor(elem, visszahívhatóFüggvény, maximálisEltérésAKezdőponttól = 15, maxMutatóSzám = 1) {
    if (!elem) {
      throw new Error('Nem adtál meg elemet')
    }

    if (!visszahívhatóFüggvény) {
      throw new Error('Nem adtál meg visszahívható függvényt')
    }

    this._ezBiztosMutató = Boolean(window.PointerEvent)

    this._elem = elem
    this._visszahívhatóFüggvény = visszahívhatóFüggvény
    this._maximálisEltérésAKezdőponttól = maximálisEltérésAKezdőponttól
    this._maxMutatóSzám = maxMutatóSzám
  }

  _tutiHogyKlikk(négyszög) {
    return Math.abs(négyszög.kezdőX - négyszög.végX) < this._maximálisEltérésAKezdőponttól &&
           Math.abs(négyszög.kezdőY - négyszög.végY) < this._maximálisEltérésAKezdőponttól
  }

  _hívjukAFüggvényt() {
    this._visszahívhatóFüggvény(this._elem)
  }

  figyelés() {
    this._mutatók = {}

    if (this._ezBiztosMutató) {
      this._elem.addEventListener('pointerdown', this._pointerDownKezelő.bind(this), false)
      this._elem.addEventListener('pointerup', this._pointerUpKezelő.bind(this), false)
    } else {
      this._elem.addEventListener('touchstart', this._touchStartKezelő.bind(this), false)
      this._elem.addEventListener('touchend', this._touchEndKezelő.bind(this), false)
    }
  }

  _pointerDownKezelő(event) {
    if (Object.keys(this._mutatók).length < this._maxMutatóSzám) {
      const négyszög = new Négyszög()
      négyszög.kezdőPont(event.clientX, event.clientY)
      this._mutatók[event.pointerId] = négyszög
    }
  }

  _pointerUpKezelő(event) {
    const négyszög = this._mutatók[event.pointerId]
    if (négyszög) {
      négyszög.végPont(event.clientX, event.clientY)

      if (this._tutiHogyKlikk(négyszög)) {
        this._hívjukAFüggvényt()
      }

      delete this._mutatók[event.pointerId]
    }
  }

  _touchStartKezelő(event) {
    for (const touch of event.changedTouches) {
      if (Object.keys(this._mutatók).length < this._maxMutatóSzám) {
        const négyszög = new Négyszög()
        négyszög.kezdőPont(touch.clientX, touch.clientY)
        this._mutatók[touch.identifier] = négyszög
      }
    }
  }

  _touchEndKezelő(event) {
    for (const touch of event.changedTouches) {
      const négyszög = this._mutatók[touch.identifier]
      if (négyszög) {
        négyszög.végPont(touch.clientX, touch.clientY)

        if (this._tutiHogyKlikk(négyszög)) {
          this._hívjukAFüggvényt()
        }

        delete this._mutatók[touch.identifier]
      }
    }
  }

  dispose() {
    this._visszahívhatóFüggvény = null
    if (this._ezBiztosMutató) {
      this._elem.removeEventListener('pointerdown')
      this._elem.removeEventListener('pointerup')
    } else {
      this._elem.removeEventListener('touchstart')
      this._elem.removeEventListener('touchend')
    }

    super.dispose()
  }
}

 

Ez a két osztály és az egyéb kód pedig függetlenül a kijelző interakciótól, valósítja meg azt a logikát amit szeretnél elérni.

 

class FuttatomASzkriptem {
  constructor(elem) {
    if (elem && this._mindenDatasetetBeállítottam(elem)) {
      this.mutatóVagyUjjbegy = new MutatóVagyUjjbegy(elem, this.fussForestFuss.bind(this))
      this.mutatóVagyUjjbegy.figyelés()
    }
  }

  // eslint-disable-next-line no-unused-vars
  fussForestFuss(elem) {
    // Az elem is elérhető ha szükséges
    window[this.szkriptem].apply(undefined, this.paramétereim)
  }

  _mindenDatasetetBeállítottam(element) {
    if (element.dataset.function) {
      this.szkriptem = element.dataset.function

      this.paramétereim = Object
        .keys(element.dataset)
        .filter(key => key.startsWith('param'))
        .map(key => element.dataset[key])

      if (typeof window[this.szkriptem] === 'function') {
        return true
      }
    }

    return false
  }

  dispose() {
    this.mutatóVagyUjjbegy?.dispose()
    super. Dispose()
  }
}

class DOMLogika {
  constructor() {
    this._szkriptjeim = []

    if (document.readyState === 'complete') {
      this._dokumentumBetöltődött()
    } else {
      document.addEventListener('DOMContentLoaded', () => this._dokumentumBetöltődött())
    }
  }

  _dokumentumBetöltődött() {
    const gombok = document.querySelectorAll('[data-function]')
    for (const gomb of gombok) {
      this._szkriptjeim.push(new FuttatomASzkriptem(gomb))
    }
  }

  dispose() {
    for (const szkript of this._szkriptjeim) {
      szkript.dispose()
    }

    super.dispose()
  }
}

window.szkript1 = function (param1, param2) {
  console.log('Ezt a szkriptet futtattam: szkript1')
  console.log(`Paraméterek: ${param1}, ${param2}`)
}

window.szkript2 = function (param1) {
  console.log('Ezt a szkriptet futtattam: szkript2')
  console.log(`Paraméter: ${param1}`)
}

window.DOMLogika = new DOMLogika()

És a hozzá tartozó html:

<!doctype html>
<html lang="hu">

<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <title>Szkript futtató demo</title>
  <style>
    .szkriptGomb {
      display: inline-block;
      padding: 10px;
      border: 1px solid black;
      margin: 10px;
      cursor: pointer;
    }
  </style>
</head>

<body>
  <h1>Szkript futtató demo</h1>

  <button aria-label="ARIA label fontos!!!" type="button" class="szkriptGomb" data-function="szkript1" data-param1="paraméter 1" data-param2="ez a második">szkript 1 gomb</button>

  <button aria-label="ARIA label fontos!!!" type="button" class="szkriptGomb" data-function="szkript2" data-param1="kettes szkript paraméter 1">szkript 2 gomb</button>

  <script src="Szkriptem.js"></script>
</body>

</html>