javascript

Creando un buscador de artículos con API de Wikipedia y VueJS

Introducción

Ya expliqué cómo consumir la API de Wikipedia por separado. Hoy veremos un ejemplo de un buscador de Wikipedia.

Lo he hecho con mi framework Javascript favorito hasta el momento: VueJS. Encima de VueJS corre VuetifyJS que simplemente proporciona componentes con el estilo Material Design.

Vamos allá.

Probar app terminada

Ya ni sé por qué le decimos a cualquier cosa “app” pero no encuentro otro nombre para nombrar las cosas. En fin, si quieres ver el proyecto terminado aquí dejo un link a codepen.

Construyendo un buscador de Wikipedia

Bueno, vamos a explicar cosa por cosa.

Herramientas utilizadas

  • VueJS, un framework de Javascript
  • API de Wikipedia
  • VuetifyJS, estilo Material design sobre VueJS
  • Lodash, sólo para no tener que escribir mi propio debounce
  • Material Icons, para los iconos

Interfaz

Quise hacerla como el buscador de Google pero al final salió otra cosa y, como me gustó, así la dejé. Puse una imagen de Wikipedia, abajo un campo para introducir texto, luego un botón para obtener un artículo aleatorio y finalmente un seleccionador de idiomas.

Traducciones

Si en la app cambiamos el idioma, veremos que la leyenda de Artículo aleatorio y Comienza a escribir cambian. Así se ve en español:

Visor de Wikipedia en español

Así en inglés:

Visor de Wikipedia en inglés

Lo mismo para otros idiomas. Cabe aclarar que saqué todo del traductor de Google jaja, así que puede que haya errores. En fin, eso no importa; lo que importa es cómo se cambia el texto.

Para ello, tenemos que remontarnos a los idiomas soportados. Puse estos:

data: () => {
        return {
            idiomas: [{
                    abreviacion: "es",
                    idioma: "Español"
                },
                {
                    abreviacion: "en",
                    idioma: "English"
                }, {
                    abreviacion: "de",
                    idioma: "Deutsch"
                }, {
                    abreviacion: "fr",
                    idioma: "Français"
                }, {
                    abreviacion: "ru",
                    idioma: "русский"
                }, {
                    abreviacion: "it",
                    idioma: "italiano"
                },
            ],
        }
    },

Y entonces, en los valores calculados de la app puse estos métodos:

computed: {
        rutaArticuloAleatorio() {
            if (!this.idiomaSeleccionado) return "";
            return `https://${this.idiomaSeleccionado.abreviacion}.wikipedia.org/wiki/Special:Random`;
        },
        rutaArticulo() {
            if (!this.idiomaSeleccionado || !this.resultadoSeleccionado) return "";
            return `https://${this.idiomaSeleccionado.abreviacion}.wikipedia.org/?curid=${this.resultadoSeleccionado.pageid}`;
        },
        leyendaArticuloAleatorio() {

            if (!this.idiomaSeleccionado) return "";
            return {
                "es": "Artículo aleatorio",
                "en": "Random article",
                "de": "Zufälliger Artikel",
                "fr": "Article aléatoire",
                "ru": "Случайная статья",
                "it": "Articolo casuale",
            }[this.idiomaSeleccionado.abreviacion];
        },
        labelBusqueda() {
            if (!this.idiomaSeleccionado) return "";
            return {
                "es": "Comienza a escribir",
                "en": "Start typing",
                "de": "Beginnen Sie zu tippen",
                "fr": "Commencez à taper",
                "ru": "Начните вводить текст",
                "it": "Inizia a digitare",
            }[this.idiomaSeleccionado.abreviacion];
        },
    },

Por el momento fijémonos en los dos últimos. Dependiendo del idioma seleccionado, regresan un valor. Es decir, es un objeto y accedemos a una de sus propiedades. Dicha propiedad puede ser “es”, “en”, etcétera.

Lo mismo aplica para la URL de búsqueda. Podemos ver que utilizamos el poder de las backticks en Javascript para regresar una URL dependiendo del idioma seleccionado.

¿y en qué momento seleccionamos un idioma por defecto? en el método mounted del ciclo de vida de nuestra aplicación:

mounted() {
        this.idiomaSeleccionado = this.idiomas[0];
    },

Seleccionamos el primer idioma que encontremos, ya después el usuario podrá elegir otro, y cuando eso pase, todo se refrescará automáticamente gracias a la reactividad de VueJS.

Búsqueda

La parte más importante de la aplicación. Detecta cuando empezamos a escribir y busca.

Detectar cambios

Con watch, vigilamos cuando cambie “busqueda”. En caso de que cambie y de que tenga un valor que no sea falso, buscaremos. Como vemos llamamos al método buscar.

watch: {
        busqueda(termino) {
            termino && this.buscar(termino);
        },
    },

Debounce

Ok. Una vez que detectamos los cambios, hacemos un debounce. Un debounce es algo así (al menos en js) como llamar a una función una única vez, en el intervalo dado. Para no complicarme las cosas utilicé lodash.

Explicando de mejor manera, si no hiciéramos un debounce, la función se llamaría el número de veces que el usuario escribiera. Si quería buscar “hola”, la función se llamaría con “h”, luego con “ho”, y así, 4 veces.

Al usuario no le importaba buscar “h” ni “ho” o “hol”, sino “hola”, pero sin querer llamó a la función 4 veces. Esto cargaría al servidor. Para ello, hacemos que sin importar cuántas veces se llame la función, sólo se llame después de medio segundo (500 milisegundos).

De esta manera, el usuario podrá buscar y su búsqueda regresará en 500 milisegundos; cosa que ni notará.

Buscar

Cuando buscamos, simplemente llamamos a la url de la api y le concatenamos el valor de la búsqueda. Esperamos a que hayan resultados y primeramente eliminamos las etiquetas HTML, luego hacemos un JSON.parse para decodificar la cadena en formato JSON y finalmente establecemos los resultados de la búsqueda a respuesta.query.search.

methods: {

        baseUrl() {
            return `https://${this.idiomaSeleccionado.abreviacion}.wikipedia.org/w/api.php?action=query&list=search&srprop=snippet&format=json&origin=*&utf8=&srsearch=`
        },
        buscar: _.debounce(function() {
            let url = `${this.baseUrl()}${encodeURIComponent(this.busqueda)}`;
            let esto = this;
            fetch(url)
                .then(function(respuesta) {
                    return respuesta.text().then(function(texto) {
                        return esto.quitarHTML(texto);
                    });
                })
                .then(function(jsonValido) {
                    let respuesta = JSON.parse(jsonValido),
      resultados = respuesta.query.search;
                    esto.resultadosBusqueda = resultados;
                });
        }, 500),
        quitarHTML(html) {
            return html.replace(/<\/?[^>]+>/gi, '');
        }

VueJS detectará el cambio y entonces mostrará la lista de resultados:

Resultados de la búsqueda | Consumiendo API de wikipedia

Cuando hacemos click, el objeto clickeado pasa a ser el valor de la variable resultadoSeleccionado.

Resultados

Como dijimos arriba, el resultado pasa a ser parte de nuestra app. Y para ello lo mostramos en la vista:

<template style="text-align:justify;" v-if="resultadoSeleccionado">
 <br>
 <span class="headline">{{resultadoSeleccionado.title}}</span>
 <p>{{resultadoSeleccionado.snippet}}...</p>
 <v-btn target="_blank" :href="rutaArticulo" flat color="light-green"><v-icon>open_in_new</v-icon></v-btn>
</template>

Utilizamos v-if para ocultarlo en caso de que no seleccionen nada. Mostramos el título y el snippet. También un botón que en realidad es un link, y que dirige al enlace que tenga la variable  rutaArticulo. Esta variable ya fue vista anteriormente, allá arriba.

Artículo aleatorio

Igualmente sólo es un link-botón definido así:

<v-btn target="_blank" :href="rutaArticuloAleatorio" flat color="light-green">{{leyendaArticuloAleatorio}}&nbsp;&nbsp;<v-icon>cached</v-icon></v-btn>

Cuyo href es la variable rutaArticuloAleatorio que ya vimos más arriba.

Otras cosas

Sólo hace falta mencionar la equis que aparece en la barra de búsqueda, cuya función es limpiar el campo de texto. Viene por defecto en el componente, así que no hace falta explicarla.

Conclusión

Espero que haya explicado todo y que no queden dudas. De todos modos, puedes dejar un comentario si algo no quedó claro. Aquí dejo el código fuente, pues es la mejor manera de estudiar el funcionamiento. Nos vemos luego.

Estoy aquí para ayudarte 🤝💻


Estoy aquí para ayudarte en todo lo que necesites. Si requieres alguna modificación en lo presentado en este post, deseas asistencia con tu tarea, proyecto o precisas desarrollar un software a medida, no dudes en contactarme. Estoy comprometido a brindarte el apoyo necesario para que logres tus objetivos. Mi correo es parzibyte(arroba)gmail.com, estoy como@parzibyte en Telegram o en mi página de contacto

No te pierdas ninguno de mis posts 🚀🔔

Suscríbete a mi canal de Telegram para recibir una notificación cuando escriba un nuevo tutorial de programación.
parzibyte

Programador freelancer listo para trabajar contigo. Aplicaciones web, móviles y de escritorio. PHP, Java, Go, Python, JavaScript, Kotlin y más :) https://parzibyte.me/blog/software-creado-por-parzibyte/

Ver comentarios

Entradas recientes

Desplegar PWA creada con Vue 3, Vite y SQLite3 en Apache

Ya te enseñé cómo convertir una aplicación web de Vue 3 en una PWA. Al…

6 días hace

Arquitectura para wasm con Go, Vue 3, Pinia y Vite

En este artículo voy a documentar la arquitectura que yo utilizo al trabajar con WebAssembly…

6 días hace

Vue 3 y Vite: crear PWA (Progressive Web App)

En un artículo anterior te enseñé a crear un PWA. Al final, cualquier aplicación que…

6 días hace

Errores de Comlink y algunas soluciones

Al usar Comlink para trabajar con los workers usando JavaScript me han aparecido algunos errores…

6 días hace

Esperar promesa para inicializar Store de Pinia con Vue 3

En este artículo te voy a enseñar cómo usar un "top level await" esperando a…

6 días hace

Solución: Apache – Server unable to read htaccess file

Ayer estaba editando unos archivos que son servidos con el servidor Apache y al visitarlos…

7 días hace

Esta web usa cookies.