2016-07-14 264 views
8

Nella mia pagina ho due tabelle di uguale larghezza e entrambe fanno lo scroll orizzontale. Devo impostare entrambe le tabelle nella stessa posizione quando ciascuna scorre.Come impostare scrollLeft in due oggetti usando defineSetter?

In realtà, il mio codice è:

var scrollA = $('#scrollA'), 
    scrollB = $('#scrollB'); 

scrollA.on('scroll', function() { 
    scrollB[0].scrollLeft = scrollA[0].scrollLeft; 
}); 

Funziona. Il problema è che ci sono situazioni in cui i dati caricati sono abbastanza grandi da rallentare il browser e l'evento di scorrimento.

Quindi, sto cercando di migliorare l'esperienza dell'utente in quelle situazioni.


ho fatto questo frammento in cui cerco di usare la funzione __defineSetter__ di Object:

var elementA = { scrollLeft: 30 }, 
 
    elementB = { scrollLeft: 30 }; 
 

 
elementA.__defineSetter__('scrollLeft', val => elementB.scrollLeft = val); 
 

 
elementA.scrollLeft += 5; 
 
console.log(elementA.scrollLeft + ' == ' + elementB.scrollLeft);

Ma come si può vedere l'esecuzione del frammento, imposta undefined-elementA.scrollLeft e NaN a elementB.scrollLeft.

Vorrei una guida qui, grazie per il vostro tempo.

+0

'__defineSetter__ è' è deprecato, usare 'defineProperty()' – zer00ne

+0

Invece di avere barra di scorrimento separato per ogni tavolo perché non può u provare a mettere entrambi in un contenitore e hanno un barra di scorrimento per quel contenitore in modo che possiamo evitare questo scenario. Sto suggerendo questo bcoz hai detto che entrambi i tavoli hanno la stessa larghezza – Varatharaj

+0

@ Varatharaj. In realtà, si tratta di un plug-in su cui sto lavorando e che blocca colonne e/o intestazioni di un tavolo ... Non posso testarlo ora, ma proverò la tua idea più tardi –

risposta

2

Gli eventi di scorrimento possono generare una frequenza elevata, pertanto è possibile ottenere uno scorrimento più fluido limitando il gestore di eventi di scorrimento, come ha detto Trincot nella sua risposta. È possibile limitare una funzione utilizzando setTimeout. Per spostare le cose sullo schermo o gestire altri effetti visibili, preferisco lo requestAnimationFrame.

requestAnimationFrame esegue la richiamata prima del successivo ridisegno, quindi il browser può eseguire alcune ottimizzazioni.

Questo codice ti porterà più vicino alla soluzione, si basa su this example from MDN:

var scrollA = $('#scrollA'), 
    scrollB = $('#scrollB'), 
    running = false; 

scrollA.on('scroll', function() { 
    // if we already requested an animation frame, do nothing 
    if (!running) { 
    window.requestAnimationFrame(function() { 
     // synchronize table B and table A 
     scrollB[0].scrollLeft = scrollA[0].scrollLeft 
     // we're done here and can request a new frame 
     running = false; 
    }); 
    } 

    running = true; 
}); 

È possibile utilizzare il timestamp passato alla callback per evitare il bouncing ulteriormente la sincronizzazione, ma si può finire con un po 'lento scorrere il secondo tavolo se si mette troppo ritardo.

2

La chiamata al __defineSetter__sostituisce la proprietà scrollLeft con uno con lo stesso nome, che significa che non è possibile raggiungere la proprietà originale più. Una volta che avete chiamato __defineSetter__, qualsiasi lettura dei risultati di proprietà in undefined:

console.log(scrollA[0].scrollLeft); // some number, like 10 
scrollA[0].__defineSetter__('scrollLeft', val => scrollB[0].scrollLeft = val) 
console.log(scrollA[0].scrollLeft); // undefined 

Inoltre, il browser non cambiare lo scrollLeft valore tramite un incarico come si farebbe in JavaScript, in modo che la funzione setter non lo farà essere chiamato durante un evento di scorrimento. È possibile verificare questo mettendo un console.log nella funzione setter: nulla viene visualizzato quando si scorre:

scrollA[0].__defineSetter__('scrollLeft', val => console.log(val)) 

Per questi due motivi non v'è alcuna speranza è possibile catturare i cambiamenti di scorrimento utilizzando __defineSetter__. Devi ascoltare l'evento scroll come hai fatto per primo.

Si potrebbe ottenere risultati migliori se si fa la sincronizzazione in modo asincrono, e saltare alcuni degli aggiornamenti quando si dispone di molti eventi di scorrimento che si verificano:

var scrollA = $('#scrollA'), 
    scrollB = $('#scrollB'), 
    tmr = -1; 

scrollA.on('scroll', function() { 
    clearTimeout(tmr); 
    tmr = setTimeout(_ => scrollB[0].scrollLeft = scrollA[0].scrollLeft, 0); 
}); 

Ora, quando il browser genera più di un evento di scorrimento all'istante, il il secondo pre-svuota l'aggiornamento programmato di scrollB[0].scrollLeft: lo clearTimeout impedirà che si verifichi l'aggiornamento e il successivo è pianificato.

Si può anche giocare con l'argomento ritardo di setTimeout per trovare il giusto equilibrio:

Aumentando il ritardo impedirà eventi da impilare, e così scrollB sarà quindi sincronizzare in modo più reattivo, ma un minor numero di aggiornamenti sarà fatto per scrollBscrollLeft proprietà, che può far scorrere in modo meno scorrevole.

+0

Sfortunatamente 'clearTimeout' non sincronizza entrambi gli scroll. Penso che agisca più come un evento 'scroll-end'. –

+0

L'uso di 'clearTimeout' non è inteso per la sincronizzazione, ma per lo svuotamento della coda di timeout. Non termina lo scorrimento, che è guidato dall'evento di scorrimento a cui sta rispondendo, e viene trattato da 'setTimeout'. Se vedi un problema, potresti dimostrarlo in un violino? – trincot

+1

@Guedes Provare a utilizzare 'requestAnimationFrame', vedere [questo esempio] (https://developer.mozilla.org/en/docs/Web/Events/scroll#Example) da MDN. Penso che non sia possibile ottenere una sincronizzazione perfetta, almeno nei dispositivi di fascia bassa – jbmartinez

0

Non farlo. Fallo un tavolo. Mantienilo semplice. Vedi esempio.

<!DOCTYPE html> 
 
<html> 
 
<head> 
 
<style> 
 
table { 
 
    font-family: arial, sans-serif; 
 
    border-collapse: collapse; 
 
    width: 2000px; 
 
} 
 

 
td, th { 
 
    border: 1px solid #dddddd; 
 
    text-align: left; 
 
    padding: 8px; 
 
} 
 

 
tr:nth-child(even) { 
 
    background-color: #dddddd; 
 
} 
 
</style> 
 
</head> 
 
<body> 
 

 
<table> 
 
    <tr> 
 
    <th>Company</th> 
 
    <th>Contact</th> 
 
    <th>Country</th> 
 
    </tr> 
 
    <tr> 
 
    <td>Alfreds Futterkiste</td> 
 
    <td>Maria Anders</td> 
 
    <td>Germany</td> 
 
    </tr> 
 
    <tr> 
 
    <td>Centro comercial Moctezuma</td> 
 
    <td>Francisco Chang</td> 
 
    <td>Mexico</td> 
 
    </tr> 
 
    <tr> 
 
    <th>Ernst Handel</th> 
 
    <th>Roland Mendel</th> 
 
    <th>Austria</th> 
 
    </tr> 
 
    <tr> 
 
    <td>Island Trading</td> 
 
    <td>Helen Bennett</td> 
 
    <td>UK</td> 
 
    </tr> 
 
    <tr> 
 
    <td>Laughing Bacchus Winecellars</td> 
 
    <td>Yoshi Tannamuri</td> 
 
    <td>Canada</td> 
 
    </tr> 
 
    <tr> 
 
    <td>Magazzini Alimentari Riuniti</td> 
 
    <td>Giovanni Rovelli</td> 
 
    <td>Italy</td> 
 
    </tr> 
 
</table> 
 

 
</body> 
 
</html>