Cómo hacer búsquedas de usuarios en GitHub usando Vue

Creo que todos ya saben cómo escribir una búsqueda en los usuarios de GitHub en React , Svelte , Angular o sin ellos . Bueno, ¿cómo puedes prescindir de Vue? Es hora de llenar este vacío.


imagen


Entonces, hoy crearemos la misma aplicación usando Vue, escribiremos pruebas para ella en Cypress y afectaremos ligeramente a Vue CLI 3.


Hay gifs en la publicación


Preparación


Para comenzar, instale el Vue CLI de la última versión:


npm i -g @vue/cli 

Y ejecuta la creación del proyecto:


 vue create vue-github-search 

Sigue los pasos del generador. Para nuestro proyecto, elegí el modo Manual y la siguiente configuración:


imagen


Módulos adicionales


Utilizaremos Stylus como estilos, por lo que necesitamos stylus y stylus-loader. También necesitamos Axios para solicitudes de red y Lodash , de donde tomaremos la función antirrebote.


Vaya a la carpeta del proyecto e instale los paquetes necesarios:


 cd vue-github-search npm i stylus stylus-loader axios lodash 

Cheque


Comenzamos el proyecto y nos aseguramos de que todo funcione:


  npm run serve 

Todos los cambios en el código se aplicarán instantáneamente en el navegador sin volver a cargar la página.


Tienda


Comencemos escribiendo vuex store, donde estarán todos los datos de la aplicación. Simplemente no debemos almacenar nada: una consulta de búsqueda, datos de usuario y un indicador del proceso de carga.
Abra store.js y describa el estado inicial de la aplicación y las mutaciones necesarias:


 ... const SET_SEARCH_QUERY = 'SET_SEARCH_QUERY'; const SET_LOADING = 'SET_LOADING'; const SET_USER = 'SET_USER'; const RESET_USER = 'RESET_USER'; export default new Vuex.Store({ state: { searchQuery: '', loading: false, user: null }, mutations: { [SET_SEARCH_QUERY]: (state, searchQuery) => state.searchQuery = searchQuery, [SET_LOADING]: (state, loading) => state.loading = loading, [SET_USER]: (state, user) => state.user = user, [RESET_USER]: state => state.user = null } }); 

Agregue acciones para cargar datos desde la API de GitHub y para modificar la consulta de búsqueda (la necesitamos para la cadena de búsqueda). Como resultado, nuestra tienda tomará la siguiente forma:


store.js


 import Vue from 'vue'; import Vuex from 'vuex'; import axios from 'axios'; Vue.use(Vuex); const SET_SEARCH_QUERY = 'SET_SEARCH_QUERY'; const SET_LOADING = 'SET_LOADING'; const SET_USER = 'SET_USER'; const RESET_USER = 'RESET_USER'; export default new Vuex.Store({ state: { searchQuery: '', loading: false, user: null }, mutations: { [SET_SEARCH_QUERY]: (state, searchQuery) => state.searchQuery = searchQuery, [SET_LOADING]: (state, loading) => state.loading = loading, [SET_USER]: (state, user) => state.user = user, [RESET_USER]: state => state.user = null }, actions: { setSearchQuery({commit}, searchQuery) { commit(SET_SEARCH_QUERY, searchQuery); }, async search({commit, state}) { commit(SET_LOADING, true); try { const {data} = await axios.get(`https://api.github.com/users/${state.searchQuery}`); commit(SET_USER, data); } catch (e) { commit(RESET_USER); } commit(SET_LOADING, false); } } }); 

Cadena de búsqueda


Cree un nuevo componente Search.vue en la carpeta de components . Agregue una propiedad calculada para asociar el componente con la tienda. Cuando cambie la consulta de búsqueda, llamaremos a la búsqueda con un rebote.


Search.vue


 <template> <input v-model="query" @input="debouncedSearch" placeholder="Enter username" /> </template> <script> import {mapActions, mapState} from 'vuex'; import debounce from 'lodash/debounce'; export default { name: 'search', computed: { ...mapState(['searchQuery']), query: { get() { return this.searchQuery; }, set(val) { return this.setSearchQuery(val); } } }, methods: { ...mapActions(['setSearchQuery', 'search']), debouncedSearch: debounce(function () { this.search(); }, 500) } }; </script> <style lang="stylus" scoped> input width 100% font-size 16px text-align center </style> 

Ahora conectaremos nuestra cadena de búsqueda al componente principal de App.vue y simultáneamente eliminaremos las líneas adicionales creadas por el generador.


App.vue


 <template> <div id="app"> <Search /> </div> </template> <script> import Search from './components/Search'; export default { name: 'app', components: { Search } }; </script> <style lang="stylus"> #app font-family 'Avenir', Helvetica, Arial, sans-serif font-smoothing antialiased margin 10px </style> 

Veamos el resultado en el navegador, asegurándonos de que todo funcione con vue-devtools:


imagen


Como puede ver, ¡tenemos toda la lógica de la aplicación lista! Ingresamos el nombre de usuario, la solicitud se ejecuta y los datos del perfil se almacenan en la tienda.


Perfil de usuario


Cree el componente User.vue y agregue lógica para indicar la carga, muestre el perfil y un error cuando no se encuentre al usuario. También agregue animaciones de transición.


User.vue
 <template> <div class="github-card"> <transition name="fade" mode="out-in"> <div v-if="loading" key="loading"> Loading </div> <div v-else-if="user" key="user"> <div class="background" :style="{backgroundImage: `url(${user.avatar_url})`}" /> <div class="content"> <a class="avatar" :href="`https://github.com/${user.login}`" target="_blank"> <img :src="user.avatar_url" :alt="user.login" /> </a> <h1>{{user.name || user.login}}</h1> <ul class="status"> <li> <a :href="`https://github.com/${user.login}?tab=repositories`" target="_blank"> <strong>{{user.public_repos}}</strong> <span>Repos</span> </a> </li> <li> <a :href="`https://gist.github.com/${user.login}`" target="_blank"> <strong>{{user.public_gists}}</strong> <span>Gists</span> </a> </li> <li> <a :href="`https://github.com/${user.login}/followers`" target="_blank"> <strong>{{user.followers}}</strong> <span>Followers</span> </a> </li> </ul> </div> </div> <div v-else key="not-found"> User not found </div> </transition> </div> </template> <script> import {mapState} from 'vuex'; export default { name: 'User', computed: mapState(['loading', 'user']) }; </script> <style lang="stylus" scoped> .github-card margin-top 50px padding 20px text-align center background #fff color #000 position relative h1 margin 16px 0 20px line-height 1 font-size 24px font-weight 500 .background filter blur(10px) opacity(50%) z-index 1 position absolute top 0 left 0 right 0 bottom 0 background-size cover background-position center background-color #fff .content position relative z-index 2 .avatar display inline-block overflow hidden background #fff border-radius 100% text-decoration none img display block width 80px height 80px .status background white ul text-transform uppercase font-size 12px color gray list-style-type none margin 0 padding 0 border-top 1px solid lightgray border-bottom 1px solid lightgray zoom 1 &:after display block content '' clear both li width 33% float left padding 8px 0 box-shadow 1px 0 0 #eee &:last-of-type box-shadow none strong display block color #292f33 font-size 16px line-height 1.6 a color #707070 text-decoration none &:hover color #4183c4 .fade-enter-active, .fade-leave-active transition opacity .5s .fade-enter, .fade-leave-to opacity 0 </style> 

Conecte nuestro componente en App.vue y disfrute del resultado:


App.vue
 <template> <div id="app"> <Search /> <User /> </div> </template> <script> import Search from './components/Search'; import User from './components/User'; export default { name: 'app', components: { User, Search } }; </script> <style lang="stylus"> #app font-family 'Avenir', Helvetica, Arial, sans-serif font-smoothing antialiased margin 10px </style> 

imagen


Pruebas


Escribiremos pruebas simples para nuestra aplicación.


tests / e2e / specs / test.js


 describe('Github User Search', () => { it('has input for username', () => { cy.visit('/'); cy.get('input'); }); it('has "User not found" caption', () => { cy.visit('/'); cy.contains('User not found'); }); it("finds Linus Torvalds' GitHub page", () => { cy.visit('/'); cy.get('input').type('torvalds'); cy.contains('Linus Torvalds'); cy.get('img'); cy.contains('span', 'Repos'); cy.contains('span', 'Gists'); cy.contains('span', 'Followers'); }); it("doesn't find nonexistent page", () => { cy.visit('/'); cy.get('input').type('_some_random_name_6m92msz23_2'); cy.contains('User not found'); }); }); 

Ejecute las pruebas con el comando


 npm run test:e2e 

En la ventana que se abre, haga clic en el botón Ejecutar todas las especificaciones y vea que las pruebas pasan:


imagen


Asamblea


Vue CLI 3 admite el nuevo modo de compilación de aplicaciones, el modo moderno. Crea 2 versiones de scripts: ligero para navegadores modernos que admiten las últimas funciones de JavaScript, y una versión completa con todos los polífilos necesarios para los más antiguos. El principal encanto es que no necesitamos molestarnos con el despliegue de dicha aplicación. Simplemente funciona Si el navegador admite <script type="module"> , levantará la compilación ligera. Cómo funciona esto, puedes leer más en este artículo .


Agregue la bandera moderna a package.json en el comando de compilación:


 "build": "vue-cli-service build --modern" 

Armar un proyecto:


 npm run build 

Veamos los tamaños de los scripts resultantes:


 8.0K ./app-legacy.cb7436d4.js 8.0K ./app.b16ff4f7.js 116K ./chunk-vendors-legacy.1f6dfb2a.js 96K ./chunk-vendors.a98036c9.js 

Como puede ver, el nuevo método realmente reduce el tamaño del ensamblaje. La diferencia será aún más notable en proyectos grandes, por lo que la característica definitivamente merece atención.


Código


Github


Demo


Eso es todo, ¡gracias por mirar!

Source: https://habr.com/ru/post/es420351/


All Articles