Implementa fácilmente un efecto de búsqueda en vivo
Spanish (Español) translation by Luis Chiabrera (you can also view the original English article)
El efecto de búsqueda en vivo no es una novedad en las aplicaciones de escritorio. En Mac OS X o Windows Vista/7, simplemente escribe algunas letras en un cuadro de búsqueda y obtendrás el resultado de la búsqueda casi al instante. Tener que presionar el botón de enviar se está volviendo de la vieja escuela.
Este tutorial te mostrará cómo llevar este efecto genial al mundo web con jQuery. El código utilizado en este tutorial se modifica según el enfoque de John Resig.

Efecto de búsqueda en vivo en Windows 7

Efecto de búsqueda en vivo en OS X
Características



- Presenta el resultado de la búsqueda sobre la marcha
- Búsqueda difusa
- Súper rápido, sin llamadas AJAX
Paso 1: el HTML
Para comenzar, necesitamos algunos elementos html que incluyen:
- Una entrada de texto, en la que escribimos nuestras consultas.
- Una lista desordenada, para mostrar el resultado de la búsqueda.
... y dos bibliotecas javascript:
- jQuery: Necesitarás al menos saber esto para completar este tutorial.
- Quicksilver Score: este maravilloso script imita el famoso algoritmo de búsqueda en vivo Quicksilver en Mac. Indica si dos cadenas de texto son relevantes y cuán relevantes. Es como un mini google en un archivo js. A todos los usuarios les gusta la búsqueda difusa, ¿verdad? Y a todos les gusta que los resultados de búsqueda se muestren desde los más relevantes hasta los menos relevantes. ¡Gracias al gran trabajo de Lachie Cox!
Por último, pero no menos importante, necesitamos algunos elementos para buscar. En este tutorial, usemos los nombres de muchos frameworks web como datos ficticios, ¿de acuerdo? (Consulta la lista de estos marcos)
Los datos de "búsqueda desde" se pueden proporcionar en matrices, JSON o de cualquier forma, siempre que se puedan recorrer en bucle en javascript. También se pueden utilizar matrices multidimensionales. Pero para facilitar la demostración y la comprensión, los datos utilizados en este tutorial son una matriz unidimensional simple llamada "elementos".
Y finalmente, aquí está el HTML. Presta atención a dónde se incluyen las dos bibliotecas JS. Nota: css no es la parte clave de este efecto, por lo que no dedicaremos un segundo a diseñar. Están minificados. Espero que esto no te moleste ni te distraiga. Centrémonos en HTML y JS.
Guarda el siguiente código en un archivo html y ¡comencemos!
1 |
|
2 |
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
|
3 |
<html>
|
4 |
<head>
|
5 |
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"> |
6 |
<title>jQuery Livesearch Effect</title> |
7 |
<style>
|
8 |
*{font-family:Tahoma,Geneva,sans-serif}body{background:#175082}h1{color:#069;font-size:40px;font-family:Georgia,"Times New Roman",Times,serif;line-height:50px;padding-bottom:10px;vertical-align:top;border-bottom:1px dashed#09F}h4{color:#000;font-size:20px;font-weight:normal}div#all{width:700px;position:relative;margin:40px auto;border:5px solid#09F;background:#DDF2FF;padding:0px 25px 50px 25px}input#q{width:300px;height:30px;line-height:30px;font-size:26px;border:2px solid#CCC;padding-left:5px}span#tip{font-size:12px;line-height:30px;margin-left:15px;color:#F30;font-weight:bold;margin-bottom:10px}ul#results li{color:#666;line-height:1.7em} |
9 |
</style>
|
10 |
</head>
|
11 |
<body>
|
12 |
<div id="all"> |
13 |
<h1>jQuery Livesearch Demo</h1> |
14 |
<h4>Find Your Favourite Web Framework</h4> |
15 |
<input id="q" /> |
16 |
<span id="tip"><-- Type in here and get search results LIVE!</span> |
17 |
<ul id="results"></ul> |
18 |
</div>
|
19 |
|
20 |
<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.3.2/jquery.min.js"></script> |
21 |
<script type="text/javascript" src="http://rails-oceania.googlecode.com/svn/lachiecox/qs_score/trunk/qs_score.js"></script> |
22 |
<script>
|
23 |
// A placeholder for the real code
|
24 |
</script>
|
25 |
<script>
|
26 |
var items = ["Agavi","AIDA Web","Akelos","Apache Click","Apache Cocoon","Apache Struts","Apache Wicket","AppFuse","Aranea","ASP.NET MVC","Axiom Stack","BFC","CakePHP","DooPHP","Camping","Catalyst","CherryPy","CodeIgniter","ColdSpring","Csla","CppCMS","CubicWeb","Django","Drupal","DotNetNuke","eZ Components","Flex","FUSE","Fusebox","Google Web Toolkit","Grok","Grails","Hamlets","Helix","Horde","Interchange","ItsNat","IT Mill Toolkit","JavaServer Faces","JBoss Seam","Kepler","Kohana","KumbiaPHP","Lift","LISA","ManyDesigns Portofino","Mason","Maypole","Mach-II","Merb","Midgard","Model-Glue","MonoRail","Morfik","Nitro","onTap","OpenACS","OpenLaszlo","OpenXava","Orbit","Orinoco","PEAR","PHP For Applications","PHP Work","Pyjamas","Pylons","Qcodo","RIFE","Ruby on Rails","Samstyle","Seaside","Shale","SilverStripe (Sapphire)","Simplicity","Sinatra","SmartClient","Sofia","SPIP","Spring","Stripes","Symfony","Tapestry","ThinWire","Tigermouse","Vaadin","TurboGears","Wavemaker","web2py","WebObjects","WebWork","Wigbi","Yii","Zend","ZK","Zoop","Zope 2","Zope 3","ztemplates"]; |
27 |
</script>
|
28 |
</body>
|
29 |
</html>
|
Paso 2: Firebug es nuestro mejor amigo!
Como usuario de JavaScript, no puedes vivir sin Firebug actualemente. Definitivamente es imprescindible para cualquiera que trabaje con jQuery. Puedse completar este tutorial sin Firebug instalado. Pero con Firebug, podemos ver muchas cosas detrás de escena, lo cual es esencial para comprender la búsqueda en este efecto.
¿Recuerdas los elementos ficticios para buscar? Sí, los nombres del marco. Comprobemos si están en el lugar correcto con Firebug:
- Abre el archivo HTML con Firefox.
- Abre Firebug y cambia al panel "Console" (ctrl+shift+c).
- Escribe "items" (sin comillas) en el cuadro de la derecha y presiona "Run".
Deberías ver algo que se muestra en la imagen a continuación. Firebug imprime la variable "items" que es una matriz. Sí, los nombres de nuestros marcos están ahí. ¡Continúemos!



Paso 3: la lógica
Ahora, hablemos de la lógica. Para que este efecto funcione, es necesario que ocurra una secuencia de cosas:
- El usuario toca una tecla.
- Obtenemos el texto del cuadro de búsqueda. Llamémoslo "query".
- Para cada nombre de marco, verificamos si la consulta es relevante y qué tan relevante es.
- Filtramos los nombres de marcos relevantes y los clasificamos según su relevancia.
- Presentamos el resultado al usuario.
Fácil, ¿eh? Salvo por una cosa. Si busco un marco llamado "cake", la lógica anterior se ejecuta, un ciclo por letra, 4 ciclos en total, ¿verdad? Pero los primeros 3 ciclos son completamente innecesarios, solo para reducir el rendimiento en gran medida. Para mitigar esto, esperaremos hasta que el usuario deje de teclear antes de activar nuestra lógica. Y si un usuario deja de teclear durante 0,2 segundos, asumimos que termina. Hasta este punto, nuestra lógica es lo suficientemente delicada. ¡Es hora de ensuciarse las manos y empezar a programar!
Paso 4: escucha de eventos
En la vida real, escuchar puede ser extremadamente importante. Esto también es cierto en el mundo de jQuery, donde todo comienza con escuchar un evento.
Busca "placeholder" en el archivo HTML. Pon el siguiente código en ese lugar.
El siguiente código escucha el evento keyup. Tíralos entre la etiqueta <script> y revisaremos algunos puntos clave. y revisaremos algunos puntos clave.
1 |
|
2 |
$(function(){
|
3 |
var t = null; |
4 |
$("#q").keyup(function(){
|
5 |
if (t) {
|
6 |
clearTimeout(t); |
7 |
} |
8 |
t = setTimeout("filter()", 200);
|
9 |
}); |
10 |
}); |
11 |
|
12 |
function filter(){
|
13 |
// Filter logic comes here |
14 |
} |
- El código se ejecuta cuando el documento está listo.
- Todas nuestras lógicas parten del evento keyup.
- ¿Recuerdas que esperaremos 0,2 segundos para ver si el usuario termina de escribir? Aquí usamos dos funciones para realizar esta característica: setTimeout() y clearTimeout(). Lo que hace setTimeout() es esperar 200ms (el segundo parámetro) antes de ejecutar una función (el primer parámetro). clearTimeout() solo le dice a setTimeout(), oye, no más esperas, solo cancélate. Si no estás familiarizado con estas funciones, estos tutoriales son excelentes. Si esta parte no tiene sentido instantáneamente para ti, no te preocupes. Repasa esos tutoriales y tómate un tiempo aquí.
- La función "filter()" calcula y ordena el resultado de la búsqueda por nosotros. Lo codificaremos en el siguiente paso.
Nota: setTimeout() es una función nativa de js. Su primer parámetro debe tener las comillas envueltas alrededor del nombre de la función, significativamente diferente de las convenciones de jQuery.
Por tanto, la función filter() se activa cuando el usuario deja de teclear durante 0,2 segundos. Ahora estamos listos para ir aún más lejos con la función filter().
Paso 5: calculando los resultados de la búsqueda
Ahora hemos llegado al núcleo de este efecto: la lógica de búsqueda, que recorre todos los nombres de los marcos y calcula la relevancia.
Coloque el siguiente código en el lugar de la función filter(). Y daremos algunas explicaciones.
1 |
|
2 |
function filter(){
|
3 |
var q = $("#q").val().toLowerCase();
|
4 |
|
5 |
scores = []; |
6 |
|
7 |
if (q.length == 0) {
|
8 |
$("#results").html("");
|
9 |
} else {
|
10 |
$.each(items, function(){
|
11 |
var score = this.toLowerCase().score(q); |
12 |
|
13 |
if (score > 0) {
|
14 |
scores.push([score, this+""]); |
15 |
} |
16 |
}); |
17 |
} |
18 |
} |
- La línea 2 no debería molestarte demasiado.Simplemente toma el texto en el cuadro de búsqueda y conviértelo a minúsculas.
- La línea 4 crea una matriz vacía llamada "scores", que se utiliza para almacenar el resultado de la búsqueda y la relevancia (o una puntuación entre la consulta y el nombre del marco).
- La línea 6-8 comprueba si la consulta está vacía (lenght = 0). Si la consulta está vacía, ni siquiera necesitamos calcular nada. Simplemente borra el área de resultados de la búsqueda.
- Desde la Línea 9, vemos algunas cosas reales. La matriz "items" lleva todos los nombres de marcos. Eso es lo que buscan los usuarios.
- La línea 9 repite "items" con $.each function. Si eres un tipo PHP, esto es similar a foreach().
- La línea 10 está en el bucle. "score" (no "scores") almacena la relevancia entre la consulta y el elemento actual (un nombre de marco). "this" aquí se refiere al elemento actual del bucle, en otras palabras, un nombre de marco. También lo cambiamos a minúsculas. Y mira la función score(). Se define en el script Quicksilver Score y calcula la relevancia para nosotros.
- La línea 12 verifica si la puntuación (relevancia) es cero. Una relevancia cero significa que los dos términos no son relevantes en absoluto. Así que simplemente los ignoramos y solo guardamos los resultados relevantes.
- La línea 13 agrega un nombre de marco con su puntuación de relevancia en conjunto a la matriz "scores".
El algoritmo Quicksilver Score distingue entre mayúsculas y minúsculas y no parece creer que "A" tenga algo que ver con "a". Asegúrate de convertir los textos a minúsculas si eso es lo que deseas.
Hasta este punto, si escribes "php" en el cuadro de búsqueda y ejecutas la variable "scores" en Firebug, obtendrás el resultado que se muestra en esta imagen.



Bueno, sé que no es el formato más atractivo del mundo, pero intentemos leerlo. Mira los números decimales. Esos son la puntuación de relevancia seguida del nombre del elemento.
Increíble, ¿eh? Pero todavía hay un problema. Mira más de cerca: CakePHP, con un puntaje de 0.42, viene antes que DooPHP(0.5) e incluso PHP Work(0.93). ¡Ese no es el orden correcto! Necesitamos arreglar esto en el siguiente paso.
Paso 6: ordenando los resultados de la búsqueda
Finalmente, aquí está la función filter() definitiva. Miremos más de cerca.
1 |
|
2 |
function filter(){
|
3 |
var q = $("#q").val().toLowerCase();
|
4 |
|
5 |
scores = []; |
6 |
|
7 |
if (q.length == 0) {
|
8 |
$("#results").html("");
|
9 |
} else {
|
10 |
$.each(items, function(){
|
11 |
var score = this.toLowerCase().score(q); |
12 |
|
13 |
if (score > 0) {
|
14 |
scores.push([score, this+""]); |
15 |
} |
16 |
}); |
17 |
if (scores.length) {
|
18 |
$("#results").html("");
|
19 |
$.each(scores.sort(function(a, b){return b[0] - a[0];}), function(i){
|
20 |
var entry = "<li>" + this[1] +"</li>"; |
21 |
$("#results").append(entry);
|
22 |
}); |
23 |
} else {
|
24 |
$("#results").html("");
|
25 |
} |
26 |
} |
27 |
} |
¡Es hora de ordenar nuestro resultado de búsqueda y presentárselo a nuestros usuarios!
- La línea 16 comprueba si "scores", nuestro contenedor de resultados de búsqueda, está vacío. Si el resultado está vacío, simplemente borramos el DOM de resultados en HTML, o si lo desea, imprimimos algunas disculpas al usuario.
- Definitivamente estamos más contentos si el resultado de la búsqueda no está vacío. En este caso, borremos el DOM de resultados en la línea 17 para dejar espacio para imprimir los resultados.
- En la línea 18, vemos un viejo amigo $.each, el iterador. Y con la función nativa js sort(), logramos ordenar los resultados de búsqueda por su relevancia. Si tienes curiosidad acerca de cómo funciona esto, consulta este documento.
- La línea 19 genera el código HTML que se agregará al DOM de resultados. Para hacerlo simple, solo agrego un LI aquí. En proyectos reales, siéntete libre de escribir HTML más complejo aquí.
- Finalmente, la línea 20 trae lo que estaba detrás de escena al frente.
Si vuelves a ejecutar la variable "scores" en Firebug, verás que se ha ordenado según la puntuación de relevancia.



Conclusión
El código utilizado en este tutorial está simplificado para facilitar la demostración. Para implementar esto en un proyecto del mundo real, considera lo siguiente:
- Agrega marcas iniciales y no encontradas para los resultados DOM
- Utiliza una matriz multidimensional como grupo de búsqueda
- Implementa HTML más complicado para la salida de resultados de búsqueda
El enfoque presentado en este tutorial se basa en el complemento Livesearch de John Resig, que toma un conjunto de LI HTML como entrada. (Tomamos matrices y JSON como entrada, lo que hace que el enfoque sea mucho más flexible). Y también gracias al algoritmo de clasificación de relevancia de texto de Lachie Cox.



