Span attribútumból szedném az functiont és a paramot, amiket szeretnék hozzáadni addEventListenerrel.
Pár sor kód, többet ér ezer szónál. Szóval íme, ahogyan nem megy:
<span data-function="scriptem" data-param="paraméter">
<script>
if(e.hasAttribute("data-function")) {
let fn = e.getAttribute("data-function");
let param = e.getAttribute("data-param");
let cb = (fn) => fn(param);
e.addEventListener('click', cb);
}
</script>
- 568 megtekintés
Hozzászólások
Ez sem segített:
let cb = fn +"('"+param+"')";
- A hozzászóláshoz be kell jelentkezni
<span data-param="paraméter" onclick="myclick(this);/>
<script>
function myclick(element) {
let params = element.getAttribute('data-param');
//handle params
}
<script>
a bindingot declaritve teszed, a handle-t meg dinamikusan. :-)
- A hozzászóláshoz be kell jelentkezni
Ezt akartam el kerülni.
Nem adok a html-hez JS-t. Azt a JS teszi. HTML csak jelzi, vannak adatai ami basztathatóak.
HTML
<span data-*="" class="clickable"></span>
Íme:
function searchClickable() {
const a_tag = document.querySelectorAll('.clickable');
a_tag.forEach((e) => {
if(e.hasAttribute("data-url")) {
let link = e.getAttribute("data-url");
let title = e.getAttribute("data-title");
e.addEventListener('click', () => {
getAjax({'link':link},{'title': title});
});
}
if(e.hasAttribute("data-function")) {
let fn = e.getAttribute("data-function");
let param = e.getAttribute("data-param");
let cb = fn +"('"+param+"')";
e.addEventListener('click', () => eval(cb));
}
});
}
window.onload = searchClickable;
- A hozzászóláshoz be kell jelentkezni
ertem, on the fly bindingolsz. A baj, h az eval-t van ahol letilt(hat)jak. Lehet egy fix router fv-t tudsz csak raaggatni es ott jatszol a contexteddel.
- A hozzászóláshoz be kell jelentkezni
A clickable-t mindig hozzaadod, vagy igy engedelyezel/tiltasz dolgokat? (data-url es a data-function meglete is eleg lehet, picit osszetettebb a selector)
A window.onload igy csak egy fuggvenyt tud hivni. Most lehet, hogy ez nem gond, kesobb azza valhat.
A getAjax visszateresi erteket lenyeled. Egyebkent ha xmlHttpRequest van meg mindig mogotte, erdemes lesz megnezned a fetch-et.
Az e.dataset.* valamivel jobb a getAttribute-nal - ahogy therion javasolta.
Jo lesz ez, hajra!
A strange game. The only winning move is not to play. How about a nice game of chess?
- A hozzászóláshoz be kell jelentkezni
Megoldás:
if(e.hasAttribute("data-function")) {
let fn = e.getAttribute("data-function");
let param = e.getAttribute("data-param");
let cb = fn +"('"+param+"')";
e.addEventListener('click', () => eval(cb));
}
Tudftam, hogy a kacsát kell megkérdeznem! :P
- A hozzászóláshoz be kell jelentkezni
Ez tuti nem a megoldas. Marmint mukodik, ertem, de ennyire nem lehet faszul megtervezve egy programnyelv, tuti kell lennie valami olyan megoldasnak is, ahol nem kell egy sztringmuveletekkel osszetakolt fuggvenyt eval()-ozni.
- A hozzászóláshoz be kell jelentkezni
Így nem lenne jobb?
if(e.hasAttribute("data-function")) {
let fn = e.getAttribute("data-function");
let param = e.getAttribute("data-param");
e.addEventListener('click', function() {
window[fn](param);
});
}
Jóval flexibilisebb, nem csak primitív adatot adhatsz át, hanem adott esetben referenciát is az elemre.
- A hozzászóláshoz be kell jelentkezni
A function es az arrow function kozti kulonbsegre figyelj! Foleg, hogy event listenerrol van szo. Gondolom Oregon nem veletlenul akart arrow functiont. (ez nem bindolja a this-t)
A {} a listener kore meg nem biztos, hogy jo otlet. A fuggveny visszateresi erteke jelenti, hogy lekezelte-e az esemenyt, vagy menjen tovabb a lancban (true vagy false). Igy return nelkul lenyeled. A sima arrow function meg {} nelkul visszater vele:
() => {return fn();} ugyanaz, mint a () => fn()
A strange game. The only winning move is not to play. How about a nice game of chess?
- A hozzászóláshoz be kell jelentkezni
Igaz!
- A hozzászóláshoz be kell jelentkezni
e.addEventListener('click', () => window[fn](param));
Ehhez mit szol a bongeszo? Milyen hibauzenetet adott amugy az eredeti? A hianyzo parametert nem talalta (fn) ugye, vagy a stringkent atadott fuggvenynevet utalta?
A strange game. The only winning move is not to play. How about a nice game of chess?
- A hozzászóláshoz be kell jelentkezni
Az eredetivel két probléma van:
- Az fn paraméter elfedi az fn lokális változót.
- Stringet nem hívhatsz függvényként.
- A hozzászóláshoz be kell jelentkezni
- A hozzászóláshoz be kell jelentkezni
Egyszer már ideje lenne végigolvasnom a manualt. :P Köszi!
- A hozzászóláshoz be kell jelentkezni
Ezt nem így kell csinálni. A "dataset" az esetedben kulcsfontosságú:
document.addEventListener('DOMContentLoaded', function() {
var spanok = document.querySelectorAll('[data-function]')
spanok.forEach(function(span) {
var scriptem = span.dataset.function
var paramétereim = Object
.keys(span.dataset)
.filter(key => key.startsWith('param'))
.map(key => span.dataset[key])
if (typeof window[scriptem] === 'function') {
window[scriptem].apply(undefined, paramétereim)
}
});
});
Valami ilyesmi.
- A hozzászóláshoz be kell jelentkezni
Szep kod. Az addEventListener viszont kimaradt, nem most akarja mind meghivni, csak amikor rakattintanak.
A strange game. The only winning move is not to play. How about a nice game of chess?
- A hozzászóláshoz be kell jelentkezni
Azt pedig a forEach belsejébe kell rakni:
spanok.forEach(function(span) {
span.addEventListener('click', function() {
Ide az előző tartalom.
}
}
- A hozzászóláshoz be kell jelentkezni
Egy gondolat ehhez a megoldáshoz. Ennél az adott use case-nél (attribútumok nem változnak betöltés után, "statikus" a HTML) lehet, hogy érdemesebb inkább a
if (typeof window[scriptem] === 'function') {
window[scriptem].apply(undefined, paramétereim)
}
részbe tenni az event listener ráaggatását, mert akkor nem kell a listenernek minden kattintáskor végigszűrni-mappelni a datasetet:
if (typeof window[scriptem] === 'function') {
span.addEventListener('click', function () {
window[scriptem].apply(undefined, paramétereim);
}
}
- A hozzászóláshoz be kell jelentkezni
Tökéletesen igazad van.
- A hozzászóláshoz be kell jelentkezni
Ezt most fogtam fel: DOMContentLoaded
- A hozzászóláshoz be kell jelentkezni
if (typeof window[scriptem] === 'function') {
Ez kód már nem megy, amióta kiraktam egy külső js-be, amit az app.js telibe behúz.
Ezt írja: Uncaught TypeError: window[e.dataset.function] is not a function
A hibaüzenetet értem, de fogalmam sincs mi okozza. Ugye a function ugyanabban a modulban van, és ráadásul már importáltam.
Felépítés:
app.js
import { my_init, searchClickable, openLayer, closeLayer } from "./base.js"
window.addEventListener("load", (event) => {
my_init();
});
Minden a base.js-ben van, a függvények export taggel el vannak látva.
Kód ami csak félig megy:
function searchClickable() {
// MEGY
document.querySelectorAll('[data-url]').forEach((e) => {
e.addEventListener('click', () => {
getAjax({'link':e.dataset.url, 'title': e.dataset.title});
});
});
// NEM MEGY
document.querySelectorAll('[data-function]').forEach((e) => {
let scriptem = e.dataset.function
let paramétereim = Object
.keys(e.dataset)
.filter(key => key.startsWith('param'))
.map(key => e.dataset[key])
if (typeof window[scriptem] === 'function') {
window[scriptem].apply(undefined, paramétereim)
console.log('kész')
} else {
console.log(scriptem) // EZ FUT LE
}
});
}
- A hozzászóláshoz be kell jelentkezni
Ez mit ir ki? Esetleg meg a tipusat is kiirathatod.
console.log(scriptem)
Felig off: azok az ekezetes elnevezesek mukodnek amugy? Sose jutott eszembe ilyet, angolul szoktam, [_a-zA-Z][_a-zA-Z0-9]* formaban. (tudom, hogy eredetileg is paramétereim volt a neve)
Az addEventListener kimaradt az alsobol.
A strange game. The only winning move is not to play. How about a nice game of chess?
- A hozzászóláshoz be kell jelentkezni
Ékezet nem gond, én sem használom a példakedvéért visszaírtam.
Lényegében annyit ír ki, hogy nincs definiálva az fv, de ez nem igaz (max a scope-ban nincs). Valami elérés változhat meg azáltal, hogy kikerült egy importálandó js-be, de ennek a működését még nem értem.
- A hozzászóláshoz be kell jelentkezni
Felig off: azok az ekezetes elnevezesek mukodnek amugy?
Én se azárt írtam magyarul mert úgy szoktam, hanem hogy a használt változók a funkcionalitástól elkülönüljön. Amúgy meg nem ACSII világban élünk már :-)
- A hozzászóláshoz be kell jelentkezni
Vanilla JS-ben nem lehet importot használni. Ahhoz hogy használd így kell a html-ben a base.js-t behúzni: (type="module")
<script type="module" src="./base.js"></script>
És a basejs-ben minden export legyen.
export function my_init...
- A hozzászóláshoz be kell jelentkezni
vagy app.js, amelyik a html-ben van az legyen module. Állítsd be a type
attribútumot "module"
-ra, hogy engedélyezd a modulrendszer használatát
- A hozzászóláshoz be kell jelentkezni
Így van berakva az app.js.
Minden export.
- A hozzászóláshoz be kell jelentkezni
A window
tartalmazza a scripteket? mert ott keresi window[a_szkriptem]
és ehhez úgy kell definiálni hogy:
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}`)
}
- A hozzászóláshoz be kell jelentkezni
Szerintem ez a baj, hogy nem. Hogyan tudom hozzáadni?
// Amúgy a base.js-ben van mindkettő, a sima getAjax megy
és exportálni?
- A hozzászóláshoz be kell jelentkezni
Afaik ami JS-ben global, az a window-hoz van hozzaadva. De nem vagyok profi javascriptes.
A strange game. The only winning move is not to play. How about a nice game of chess?
- A hozzászóláshoz be kell jelentkezni
- A hozzászóláshoz be kell jelentkezni
Ha egy függvény csak egy modulon belül létezik, és nincs globálisan hozzáadva a window objektumhoz, akkor azt nem lehet közvetlenül a window objektum segítségével meghívni. Azaz, ha egy függvényt modulban definiálsz, akkor az alapvetően csak az adott modulon belül lesz látható, és nem lesz globálisan elérhető.
- A hozzászóláshoz be kell jelentkezni
Hogyan tehetem globálissá? export kevésnek tűnik..
- A hozzászóláshoz be kell jelentkezni
Fentebb irta:
function xy(...) {...} helyett window.xy = function(...) {...}
vagy ha mar adott a function xy(...) {...}, akkor utana: window.xy = xy;
A strange game. The only winning move is not to play. How about a nice game of chess?
- A hozzászóláshoz be kell jelentkezni
a base.js-ben ilyeneket csinálj:
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}`)
}
és csak ezt írd az app.js-be:
import "./base.js";
Talán...???
- A hozzászóláshoz be kell jelentkezni
Köszönöm megy. Bénáztam. Ilyenkor ki kell szedni az export, importból mindent ami már globál.
- A hozzászóláshoz be kell jelentkezni
Nagyon köszi mindenkinek. Hasznos volt. Már látom az elvi hibámat is, miért lett olyan szegény ember frameworkje életérzésű.
Bővebben:
Szeretném, ha nem lenne JS kód a HTML-ben, de ugye a dataset-be csak berakok egy JS-ből származó fn nevet.
Elvárás/Probléma:
Szeretném a projektet pure kóddal készíteni. Illetve minden ami egységes és visszatérő az is saját kód legyen. Semmi 3rd party.
- A hozzászóláshoz be kell jelentkezni
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>
- A hozzászóláshoz be kell jelentkezni
Köszi, hogy ennyi munkát beleteszel. Sokat fogok belőle tanulni azt már látom. Sajnos az agyam mára kuka. Holnap ezzel kezdek.
A C# jó cucc, a VStudio még jobb, de együtt talán leghatékonyabb eszközrendszer. Egyelőre maradok a php-nál, mert 1998 óta ebben van kb minden üzleti dolgom. Viszont idén beleszerettem a JS-be, mert már nem full szopás benne fejleszteni (Vanilla) és lényegében két meghatározó böngésző engine van. Ha minden mást lerszarok (ezt megtehetem), akkor elég ha a felhasználó egy kb 5 évnél fiatalabb eszközzel érkezik és menni fog minden. Jól gondolom?
MDN-t elkezdtem olvasni, mert sok hiányosságom van a témában. (Nem szakmám, 5-10 évente készítek UI-t)
- A hozzászóláshoz be kell jelentkezni
Ahhoz hogy dönts hogy mi az a browser mennyiség és verzió amit támogatni akarsz, erre a .browserslistrc fájl szolgál, erről itt olvashatsz: https://github.com/browserslist/browserslist#readme
Nézd meg hogy a fejlesztő környezeted hogyan támogatja.
Én se foglalkozok olyan dolgokkal, ami nem kompatibilis. Az ügyfél nem fizeti ki ezeknek a hibáknak a kezelését, túl sokba kerül ezt karbantartani.
én ezt használom a .browserslistrc fájlban, amit a bootstrap-ből loptam anno (https://github.com/twbs/bootstrap/blob/main/.browserslistrc), és bőven elég:
>= 0.5%
last 2 major versions
not dead
Chrome >= 60
Firefox >= 60
Firefox ESR
iOS >= 12
Safari >= 12
not Explorer <= 11
- A hozzászóláshoz be kell jelentkezni
Kód felfogva, mdn elolvasva. Azt látom, hogy jelenleg nem kell nekem a pointer kezelés. Később, amikor az egyik alkalmazásban majd alaíratni szeretnék, ott majd igen. Köszi, hogy ilyen sok időt szántál rám. Ügyfelek nagyrésze desktopot használ. Ugyanis ez egy b2b webshop.
Az alapötletről mi a véleményed? Buktatók?
Egy régi php-s alkalmazást akarok vele felfrissíteni, hogy ne legyen állandóan oldalbetöltés.
- A hozzászóláshoz be kell jelentkezni