Cómo crear una experiencia de desplazamiento infinito con la API History Web
Spanish (Español) translation by Elías Nicolás (you can also view the original English article)
En este tutorial vamos a reforzar nuestras habilidades de la API de History Web. Vamos a construir un patrón UX en la Web que es amado y detestado en igual medida: desplazamiento infinito.
El desplazamiento infinito es un patrón de interfaz que carga un nuevo contenido a medida que llegamos al final de una página web dada. El desplazamiento infinito puede retener la participación de los usuarios cuando se implementa cuidadosamente; Algunos de los mejores ejemplos que se encuentran en las plataformas sociales como Facebook, Twitter y Pinterest.
Sin embargo, vale la pena señalar que estamos tomando las cosas en un punto significativo de lo que construimos en nuestro tutorial anterior, Transiciones de páginas suaves y bonitas con la API History Web . En este tutorial vamos a tratar con la interacción de desplazamiento de los usuarios, que puede ocurrir a una velocidad muy frecuente. Si no estamos teniendo cuidado con nuestro código, impactara perjudicando el rendimiento del sitio web . Asegúrese de leer los tutoriales anteriores antes de intentar este, sólo para darle una comprensión adecuada de lo que estamos haciendo.


WordPressCómo integrar SmoothState.js en un tema de WordPressThoriq Firdaus

JavaScriptTransiciones de páginas suaves y bonitas con la API History WebThoriq Firdaus
Sin embargo, si está emocionado con la idea de un desafío, ajuste su cinturón de seguridad, prepárese, y ¡vamos a empezar!
Creación del sitio web de demostración
Nuestro sitio es un blog estático. Puede crearlo desde HTML simple o aprovechar un generador estático de sitios como Jekyll, Middleman o Hexo. Nuestra demostración para este tutorial tiene el siguiente aspecto:



Hay un par de cosas con respecto a la estructura HTML que requieren su atención.
1 |
<!-- site header -->
|
2 |
<div class="content" id="main"> |
3 |
<article class="article" id="article-5" data-article-id="5"> |
4 |
<!-- content -->
|
5 |
</article>
|
6 |
<!-- site footer -->
|
- Como se puede ver en el fragmento de código anterior, el artículo debe estar incluido en un elemento HTML con un ID único. Puede utilizar un
divo un elementosection, sin restricción en el termino a nombrar eliddel elemento. - Además,
en el propio artículo, deberá agregar un atributo
data-article-idque contenga el número deidcorrespondiente del artículo.
Siéntase libre de crear los estilos del sitio web; Lo que lo haga más colorido, atractivo o agregar más contenido.
Cargar JavaScript
Para empezar, cargue las siguientes bibliotecas JavaScript en el siguiente orden en cada página de su blog.
- Jquery.js: la biblioteca que usaremos para seleccionar elementos, añadir nuevos contenidos, agregar nueva clase y realizar solicitudes AJAX.
- History.js: un polyfill que ajusta el API de history nativo de los navegadores.
Nuestro complemento jQuery personalizado
Además de estos dos, tendremos que cargar nuestro propio archivo JavaScript donde podemos escribir los scripts para realizar desplazamientos infinitos. El enfoque que vamos a tomar es envolver nuestro JavaScript en un plugin jQuery, en lugar de escribirlo directamente como hemos hecho en los tutoriales anteriores.
Comenzaremos el plugin con el Plugin jQuery Boilerplate. Esto se asemeja a HTML5 Boilerplate en que proporciona una colección de plantillas, patrones y mejores prácticas sobre las cuales construir un plugin jQuery.
Descargue
el Boilerplate, colóquelo en el directorio de su sitio web donde
residen todos los archivos JavaScript (como /assets/js/) y cambie el
nombre del archivo a "keepscrolling.jquery.js" (Este nombre fue inspirado por Dory de Buscando a Nemo y su famosa línea "Keep Swimming").
1 |
assets/js |
2 |
├── keepscrolling.jquery.js |
3 |
├── keepscrolling.jquery.js.map |
4 |
└── src |
5 |
└── keepscrolling.jquery.js |
El complemento nos permitirá introducir flexibilidad con Opciones o Configuración.
Observando la estructura del Plugin jQuery
Escribir un plugin jQuery requiere una forma de pensar ligeramente diferente, por lo que primero examinaremos cómo nuestro plugin jQuery está estructurado antes de agregar cualquier código. Como se puede ver a continuación, he dividido el código en cuatro secciones:
1 |
;( function( $, window, document, undefined ) { |
2 |
|
3 |
"use strict"; |
4 |
|
5 |
// 1.
|
6 |
var pluginName = "keepScrolling", |
7 |
defaults = {}; |
8 |
|
9 |
// 2.
|
10 |
function Plugin ( element, options ) { |
11 |
|
12 |
this.element = element; |
13 |
this.settings = $.extend( {}, defaults, options ); |
14 |
|
15 |
this._defaults = defaults; |
16 |
this._name = pluginName; |
17 |
|
18 |
this.init(); |
19 |
}
|
20 |
|
21 |
// 3.
|
22 |
$.extend( Plugin.prototype, { |
23 |
init: function() { |
24 |
console.log( "Plugin initialized" ); |
25 |
},
|
26 |
} ); |
27 |
|
28 |
// 4.
|
29 |
$.fn[ pluginName ] = function( options ) { |
30 |
return this.each( function() { |
31 |
if ( !$.data( this, "plugin_" + pluginName ) ) { |
32 |
$.data( this, "plugin_" + |
33 |
pluginName, new Plugin( this, options ) ); |
34 |
}
|
35 |
} ); |
36 |
};
|
37 |
|
38 |
} )( jQuery, window, document ); |
- En
la primera sección del código, especificamos nuestro nombre de plugin,
keepScrolling, con "camel case" de acuerdo con las convenciones de nombres comunes de JavaScript. También tenemos una variable,defaults, que contendrá la configuración predeterminada del complemento. - A continuación, tenemos la función principal del complemento,
Plugin(). Esta función se puede comparar con un "constructor" que, en este caso, inicializa el complemento y fusionar los valores predeterminados con los que se pasen al instanciar el complemento. - La tercera sección es donde vamos a componer nuestras propias funciones para servir a la funcionalidad de desplazamiento infinito.
- Por último, la cuarta sección es una que envuelve todo el asunto en un complemento jQuery.
Con todos estos conjuntos, ahora podemos componer nuestro JavaScript. Y comenzamos definiendo las opciones predeterminadas de nuestro complemento.
Las opciones
1 |
;( function( $, window, document, undefined ) { |
2 |
|
3 |
"use strict"; |
4 |
|
5 |
var pluginName = "keepScrolling", |
6 |
defaults = { |
7 |
floor: null, |
8 |
article: null, |
9 |
data: {} |
10 |
};
|
11 |
...
|
12 |
|
13 |
} )( jQuery, window, document ); |
Como puede ver arriba, hemos establecido tres opciones:
-
floor: un selector de id–como#flooro#footer- que consideramos el final del sitio web o el contenido. Normalmente, sería el pie de página del sitio. -
article: un selector de clase que envuelve el artículo. -
data: dado que no tenemos acceso a ninguna API externa (nuestro sitio web es estático) necesitamos pasar una colección de datos de artículo, como la URL del artículo, el ID y el título en formato JSON como argumento de opción.
Las funciones
Aquí tenemos el init(). En esta función, agregaremos una serie de funciones que deben ejecutarse inmediatamente durante la inicialización del sitio. Por ejemplo, seleccionamos el piso del sitio.
1 |
$.extend( Plugin.prototype, { |
2 |
|
3 |
// The `init()` function.
|
4 |
init: function() { |
5 |
this.siteFloor = $( this.settings.floor ); // select the element set as the site floor. |
6 |
},
|
7 |
} ); |
También hay algunas funciones que ejecutaremos fuera de la inicialización. Añadimos estas funciones para crearlas y agregarlas después de la función init.
El primer conjunto de funciones que vamos a escribir son las que utilizamos para recuperar o devolver una "cosa"; Cualquier cosa desde una Cadena, un Objeto o un Número que pueda reutilizarse en las otras funciones del complemento. Estos incluyen cosas para:
Obtener todos los artículos en la página:
1 |
/**
|
2 |
* Find and returns list of articles on the page.
|
3 |
* @return {jQuery Object} List of selected articles.
|
4 |
*/
|
5 |
getArticles: function() { |
6 |
return $( this.element ).find( this.settings.article ); |
7 |
},
|
Obtenga la dirección del artículo. En WordPress, esto se conoce popularmente como "post slug".
1 |
/**
|
2 |
* Returns the article Address.
|
3 |
* @param {Integer} i The article index.
|
4 |
* @return {String} The article address, e.g. `post-two.html`
|
5 |
*/
|
6 |
getArticleAddr: function( i ) { |
7 |
|
8 |
var href = window.location.href; |
9 |
var root = href.substr( 0, href.lastIndexOf( "/" ) ); |
10 |
|
11 |
return root + "/" + this.settings.data[ i ].address + ".html"; |
12 |
},
|
Obtenga la siguiente id y direcciónes del artículo a obtener.
1 |
/**
|
2 |
* Return the "next" article.
|
3 |
* @return {Object} The `id` and `url` of the next article.
|
4 |
*/
|
5 |
getNextArticle: function() { |
6 |
|
7 |
// Select the last article.
|
8 |
var $last = this.getArticles().last(); |
9 |
|
10 |
var articlePrevURL; |
11 |
|
12 |
/**
|
13 |
* This is a simplified way to determine the content ID.
|
14 |
*
|
15 |
* Herein, we substract the last post ID by `1`.
|
16 |
* Ideally, we should be calling call an API endpoint, for example:
|
17 |
* https://www.techinasia.com/wp-json/techinasia/2.0/posts/329951/previous/
|
18 |
*/
|
19 |
var articleID = $last.data( "article-id" ); |
20 |
var articlePrevID = parseInt( articleID, 10 ) - 1; // Previous ID |
21 |
|
22 |
// Loop into the Option `data`, and get the correspending Address.
|
23 |
for ( var i = this.settings.data.length - 1; i >= 0; i-- ) { |
24 |
if ( this.settings.data[ i ].id === articlePrevID ) { |
25 |
articlePrevURL = this.getArticleAddr( i ) ; |
26 |
}
|
27 |
}
|
28 |
|
29 |
return { |
30 |
id: articlePrevID, |
31 |
url: articlePrevURL |
32 |
};
|
33 |
},
|
A continuación se muestran las funciones de utilidad del complemento; Una función que es responsable de hacer una "cosa" particular. Éstas incluyen:
Función que indica si un elemento está entrando en la ventana gráfica. Lo usamos principalmente para saber si el sitio definido "piso" es visible dentro de la ventana gráfica.
1 |
/**
|
2 |
* Detect whether the target element is visible.
|
3 |
* https://stackoverflow.com/q/123999/
|
4 |
*
|
5 |
* @return {Boolean} `true` if the element in viewport, and `false` if not.
|
6 |
*/
|
7 |
isVisible: function() { |
8 |
if ( target instanceof jQuery ) { |
9 |
target = target[ 0 ]; |
10 |
}
|
11 |
|
12 |
var rect = target.getBoundingClientRect(); |
13 |
|
14 |
return rect.bottom > 0 && |
15 |
rect.right > 0 && |
16 |
rect.left < ( window.innerWidth || document.documentElement.clientWidth ) && |
17 |
rect.top < ( window.innerHeight || document.documentElement.clientHeight ); |
18 |
}, |
Función que detiene la ejecución de una función; Conocido como rebote. Como
se mencionó anteriormente, nos ocuparemos de la actividad de
desplazamiento del usuario que se producirá a una velocidad muy
frecuente. Por
lo tanto, una función dentro del evento de scroll se ejecutará
con frecuencia, siguiendo el desplazamiento del usuario, que convertirá
la experiencia de desplazamiento en el sitio lento o atrasado.
La función de rebote anterior reducirá la frecuencia de ejecución. Esperará
el tiempo especificado, a través del parámetro wait, después de que el
usuario deje de desplazarse antes de ejecutar la función.
1 |
/**
|
2 |
* Returns a function, that, as long as it continues to be invoked, will not b
|
3 |
* triggered.
|
4 |
* The function will be called after it stops being called for N milliseconds.
|
5 |
* If immediate is passed, trigger the function on the leading edge, instead of
|
6 |
* the trailing.
|
7 |
*
|
8 |
* @link https://davidwalsh.name/function-debounce
|
9 |
* @link http://underscorejs.org/docs/underscore.html#section-83
|
10 |
*
|
11 |
* @param {Function} func Function to debounce
|
12 |
* @param {Integer} wait The time in ms before the Function run
|
13 |
* @param {Boolean} immediate
|
14 |
* @return {Void}
|
15 |
*/
|
16 |
isDebounced: function( func, wait, immediate ) { |
17 |
var timeout; |
18 |
|
19 |
return function() { |
20 |
|
21 |
var context = this, |
22 |
args = arguments; |
23 |
|
24 |
var later = function() { |
25 |
timeout = null; |
26 |
if ( !immediate ) { |
27 |
func.apply( context, args ); |
28 |
}
|
29 |
};
|
30 |
|
31 |
var callNow = immediate && !timeout; |
32 |
|
33 |
clearTimeout( timeout ); |
34 |
timeout = setTimeout( later, wait ); |
35 |
|
36 |
if ( callNow ) { |
37 |
func.apply( context, args ); |
38 |
}
|
39 |
};
|
40 |
}, |
Función que determina si se debe proceder o anular una operación.
1 |
/**
|
2 |
* Whether to proceed ( or not to ) fetching a new article.
|
3 |
* @return {Boolean} [description]
|
4 |
*/
|
5 |
isProceed: function() { |
6 |
|
7 |
if ( articleFetching // check if we are currently fetching a new content. |
8 |
|| articleEnding // check if no more article to load. |
9 |
|| !this.isVisible( this.siteFloor ) // check if the defined "floor" is visible. |
10 |
) { |
11 |
return; |
12 |
}
|
13 |
|
14 |
if ( this.getNextArticle().id <= 0 ) { |
15 |
articleEnding = true; |
16 |
return; |
17 |
}
|
18 |
|
19 |
return true; |
20 |
},
|
Utilizaremos
la función de utilidad anterior, isProceed(), para examinar si se
cumplen todas las condiciones para proceder a extraer nuevo contenido. Si es así, la función que sigue se ejecutará, buscara el nuevo contenido y lo añadira después del último artículo.
1 |
/**
|
2 |
* Function to fetch and append a new article.
|
3 |
* @return {Void}
|
4 |
*/
|
5 |
fetch: function() { |
6 |
|
7 |
// Shall proceed or not?
|
8 |
if ( !this.isProceed() ) { |
9 |
return; |
10 |
}
|
11 |
|
12 |
var main = this.element; |
13 |
var $articleLast = this.getArticles().last(); |
14 |
|
15 |
$.ajax( { |
16 |
url: this.getNextArticle().url, |
17 |
type: "GET", |
18 |
dataType: "html", |
19 |
beforeSend: function() { |
20 |
articleFetching = true; |
21 |
}
|
22 |
} ) |
23 |
|
24 |
/**
|
25 |
* When the request is complete and it successly
|
26 |
* retrieves the content, we append the content.
|
27 |
*/
|
28 |
.done( function( res ) { |
29 |
$articleLast
|
30 |
.after( function() { |
31 |
if ( !res ) { |
32 |
return; |
33 |
}
|
34 |
return $( res ).find( "#" + main.id ).html(); |
35 |
} ); |
36 |
} ) |
37 |
|
38 |
/**
|
39 |
* When the function is complete, whether it `fail` or `done`,
|
40 |
* always set the `articleFetching` to false.
|
41 |
* It specifies that we are done fetching the new content.
|
42 |
*/
|
43 |
.always( function() { |
44 |
articleFetching = false; |
45 |
} ); |
46 |
},
|
Agregue esta función dentro del init. Así
que la función se ejecutará tan pronto como el complemento se
inicialice, y luego recuperara el nuevo contenido cuando se cumplen las
condiciones.
1 |
init: function() { |
2 |
this.siteFloor = $( this.settings.floor ); // select the element set as the site floor. |
3 |
this.fetch(); |
4 |
},
|
A continuación, agregamos una función para cambiar el historial del navegador con la API History Web. Esta función particular es más compleja que nuestras funciones anteriores. La parte complicada aquí es cuando exactamente debemos cambiar el historial durante el desplazamiento del usuario, el título del documento, así como la URL. La siguiente es una ilustración para ayudar a simplificar la idea detrás de la función:



Como se puede ver en la figura, tenemos tres líneas: "roof-line", "mid-line" y "floor-line" que ilustran la posición del artículo dentro de la ventana gráfica. La imagen muestra que la parte inferior del primer artículo, así como la parte superior del segundo artículo, está ahora en la línea media. No especifica la intención del usuario en cuanto a qué artículo está mirando; ¿Es el primer post o es el segundo post? Por lo tanto, no cambiaríamos el historial del navegador cuando dos artículos están en esta posición.
Registraremos la historia en el post posterior cuando la parte superior del artículo llegue a la "roof-line", ya que ocupa la mayor parte de la parte visible de la ventana gráfica.



Grabamos la historia del post anterior cuando su fondo llega a la "floor-line", de manera similar, ya que ahora toma la mayor parte de la parte visible del visor.



Éste es el código "while" que necesitará agregar:
1 |
init: function() { |
2 |
this.roofLine = Math.ceil( window.innerHeight * 0.4 ); // set the roofLine; |
3 |
this.siteFloor = $( this.settings.floor ); |
4 |
this.fetch(); |
5 |
},
|
6 |
/**
|
7 |
* Change the browser history.
|
8 |
* @return {Void}
|
9 |
*/
|
10 |
history: function() { |
11 |
|
12 |
if ( !window.History.enabled ) { |
13 |
return; |
14 |
}
|
15 |
|
16 |
this.getArticles() |
17 |
.each( function( index, article ) { |
18 |
|
19 |
var scrollTop = $( window ).scrollTop(); |
20 |
var articleOffset = Math.floor( article.offsetTop - scrollTop ); |
21 |
|
22 |
if ( articleOffset > this.threshold ) { |
23 |
return; |
24 |
}
|
25 |
|
26 |
var articleFloor = ( article.clientHeight - ( this.threshold * 1.4 ) ); |
27 |
articleFloor = Math.floor( articleFloor * -1 ); |
28 |
|
29 |
if ( articleOffset < articleFloor ) { |
30 |
return; |
31 |
}
|
32 |
|
33 |
var articleID = $( article ).data( "article-id" ); |
34 |
articleID = parseInt( articleID, 10 ); |
35 |
|
36 |
var articleIndex; |
37 |
for ( var i = this.settings.data.length - 1; i >= 0; i-- ) { |
38 |
if ( this.settings.data[ i ].id === articleID ) { |
39 |
articleIndex = i; |
40 |
}
|
41 |
}
|
42 |
|
43 |
var articleURL = this.getArticleAddr( articleIndex ); |
44 |
|
45 |
if ( window.location.href !== articleURL ) { |
46 |
var articleTitle = this.settings.data[ articleIndex ].title; |
47 |
window.History.pushState( null, articleTitle, articleURL ); |
48 |
}
|
49 |
}.bind( this ) ); |
50 |
},
|
Por último, creamos una función que ejecutará el fetch() y el history() cuando el usuario está desplazando la página. Para ello creamos una nueva función llamada scroller(), y lo ejecutamos en la inicialización del complemento.
1 |
/**
|
2 |
* Functions to run during the scroll.
|
3 |
* @return {Void}
|
4 |
*/
|
5 |
scroller: function() { |
6 |
window.addEventListener( "scroll", this.isDebounced( function() { |
7 |
this.fetch(); |
8 |
this.history(); |
9 |
}, 300 ).bind( this ), false ); |
10 |
}
|
Y como se puede ver más arriba, nosotros debounce estos como realizar AJAX y cambiar el historial del navegador son una operación costosa.
Adición de un marcador de posición de contenido
Esto es opcional, pero es recomendado para respetar la experiencia del usuario. El marcador de posición proporciona comentarios al usuario, señalando que un nuevo artículo está en camino.
En primer lugar, creamos en la plantilla el marcador de posición. Comúnmente este tipo de plantilla se pone después del pie de página del sitio.
1 |
<script type="text/template" id="tmpl-placeholder"> |
2 |
<div class="placeholder placeholder--article" id="placeholder-article"> |
3 |
<div class="container"> |
4 |
<div class="placeholder__header animated"> |
5 |
<h1></h1> |
6 |
</div> |
7 |
<div> |
8 |
<p class="placeholder__p-1 animated"></p> |
9 |
<p class="placeholder__p-2 animated"></p> |
10 |
</div> |
11 |
</div> |
12 |
</div> |
13 |
</script>
|
Tenga en cuenta que el artículo de marcador de posición, su estructura, debe parecerse al contenido real de su blog. Ajuste la estructura HTML en consecuencia.
Los estilos del marcador de posición son más sencillos. Comprende
todos los estilos básicos para presentarlo como el artículo real, la
animación @keyframe que simula el sentido de carga, y el estilo para
cambiar la visibilidad (el marcador de posición se oculta inicialmente,
se muestra sólo cuando el elemento padre tiene la clase fetching).
1 |
.placeholder { |
2 |
color: @gray-light; |
3 |
padding-top: 60px; |
4 |
padding-bottom: 60px; |
5 |
border-top: 6px solid @gray-lighter; |
6 |
display: none; |
7 |
.fetching & { |
8 |
display: block; |
9 |
}
|
10 |
p { |
11 |
display: block; |
12 |
height: 20px; |
13 |
background: @gray-light; |
14 |
}
|
15 |
&__header { |
16 |
animation-delay:.1s; |
17 |
h1 { |
18 |
height: 30px; |
19 |
background-color: @gray-light; |
20 |
}
|
21 |
}
|
22 |
&__p-1 { |
23 |
animation-delay:.2s; |
24 |
width: 80%; |
25 |
}
|
26 |
&__p-2 { |
27 |
animation-delay:.3s; |
28 |
width: 70%; |
29 |
}
|
30 |
}
|
A continuación, actualizar algunas líneas para mostrar el marcador de posición durante la solicitud AJAX, como sigue.
1 |
/**
|
2 |
* Initialize.
|
3 |
* @return {Void}
|
4 |
*/
|
5 |
init: function() { |
6 |
|
7 |
this.roofLine = Math.ceil( window.innerHeight * 0.4 ); |
8 |
this.siteFloor = $( this.settings.floor ); |
9 |
|
10 |
this.addPlaceholder(); |
11 |
|
12 |
this.fetch(); |
13 |
this.scroller(); |
14 |
},
|
15 |
|
16 |
/**
|
17 |
* Append the addPlaceholder.
|
18 |
* Placeholder is used to indicate a new post is being loaded.
|
19 |
* @return {Void}
|
20 |
*/
|
21 |
addPlaceholder: function() { |
22 |
|
23 |
var tmplPlaceholder = document.getElementById( "tmpl-placeholder" ); |
24 |
tmplPlaceholder = tmplPlaceholder.innerHTML; |
25 |
|
26 |
$( this.element ).append( tmplPlaceholder ); |
27 |
},
|
28 |
|
29 |
/**
|
30 |
* Function to fetch and append a new article.
|
31 |
* @return {Void}
|
32 |
*/
|
33 |
fetch: function() { |
34 |
...
|
35 |
|
36 |
// Select the element wrapping the article.
|
37 |
var main = this.element; |
38 |
|
39 |
$.ajax( { |
40 |
|
41 |
...
|
42 |
|
43 |
beforeSend: function() { |
44 |
|
45 |
...
|
46 |
// Add the 'fetching' class.
|
47 |
$( main ).addClass( function() { |
48 |
return "fetching"; |
49 |
} ); |
50 |
}
|
51 |
} ) |
52 |
|
53 |
...
|
54 |
|
55 |
.always( function() { |
56 |
|
57 |
...
|
58 |
// Remove the 'fetching' class.
|
59 |
$( main ).removeClass( function() { |
60 |
return "fetching"; |
61 |
} ); |
62 |
} ); |
¡Así es como manejamos el marcador de posición! Nuestro complemento está completo, y es el momento de implementar el complemento.
Implementación
Implementar el complemento es bastante sencillo. Designamos el elemento que envuelve nuestro artículo de blog y llamamos a nuestro complemento con el conjunto de opciones, de la siguiente manera.
1 |
$( document ).ready( function() { |
2 |
$( "#main" ).keepScrolling({ |
3 |
floor: "#footer", |
4 |
article: ".article", |
5 |
data : [{ |
6 |
"id": 1, |
7 |
"address": "post-one", |
8 |
"title": "Post One" |
9 |
}, { |
10 |
"id": 2, |
11 |
"address": "post-two", |
12 |
"title": "Post Two" |
13 |
}, { |
14 |
"id": 3, |
15 |
"address": "post-three", |
16 |
"title": "Post Three" |
17 |
}, { |
18 |
"id": 4, |
19 |
"address": "post-four", |
20 |
"title": "Post Four" |
21 |
}, { |
22 |
"id": 5, |
23 |
"address": "post-five", |
24 |
"title": "Post Five" |
25 |
}]
|
26 |
});
|
27 |
} ); |
El rollo infinito debería estar funcionando.



Advertencia: el botón Atrás
En este tutorial, hemos construido una experiencia de desplazamiento infinita; Algo que comúnmente se ve en los sitios de noticias como Quartz, TechInAsia y en muchas aplicaciones móviles.
Aunque se ha demostrado que es una forma efectiva de retener la participación de los usuarios, también tiene un inconveniente: rompe el botón "Atrás" en el navegador. Al hacer clic en el botón, no siempre se desplaza con precisión de nuevo al contenido o página visitada anterior.
Los sitios web tratan esta cuestión de varias maneras; Quartz, por ejemplo, te redirigirá a la dirección URL referida; La URL que se visitó anteriormente, pero no está registrada a través de la API de History . TechInAsia simplemente lo llevará de vuelta a la página principal.
Terminando
Este tutorial es largo, ¡cubriendo muchas cosas! Algunos de ellos son fáciles de entender, mientras que algunas piezas pueden no ser tan fáciles de digerir. Para ayudar, he reunido una lista de referencias como un suplemento a este artículo.
- Manipulación del historial del navegador
- Transiciones de páginas suaves y bonitas con la API de History Web
- ¿Puede alguien explicar la función "debounce" en Javascript?
- AJAX para diseñadores Front-End
- Desarrollo de complementos jQuery: mejores prácticas
Por último, ¡mira en el código fuente completo y vea la demostración!



