Ich denke, jeder weiß bereits, wie man eine Suche nach GitHub-Benutzern auf React , Svelte , Angular oder überhaupt ohne sie schreibt. Wie kann man ohne Vue auskommen? Es ist Zeit, diese Lücke zu schließen.

Daher werden wir heute dieselbe Anwendung mit Vue erstellen, Tests auf Cypress schreiben und Vue CLI 3 geringfügig beeinflussen.
Es gibt Gifs in der Post
Vorbereitung
Installieren Sie zunächst die Vue-CLI der neuesten Version:
npm i -g @vue/cli
Führen Sie die Erstellung des Projekts aus:
vue create vue-github-search
Befolgen Sie die Schritte des Generators. Für unser Projekt habe ich den manuellen Modus und die folgende Konfiguration gewählt:

Zusätzliche Module
Wir werden Stylus als Stile verwenden, daher benötigen wir Stylus und Stylus-Loader. Wir benötigen Axios auch für Netzwerkanfragen und Lodash , von denen wir die Entprellungsfunktion übernehmen werden.
Gehen Sie zum Projektordner und installieren Sie die erforderlichen Pakete:
cd vue-github-search npm i stylus stylus-loader axios lodash
Überprüfen Sie
Wir starten das Projekt und stellen sicher, dass alles funktioniert:
npm run serve
Alle Änderungen am Code werden sofort im Browser übernommen, ohne die Seite neu zu laden.
Speichern
Beginnen wir mit dem Schreiben des vuex-Speichers, in dem sich alle Anwendungsdaten befinden. Wir müssen nur nichts speichern: eine Suchabfrage, Benutzerdaten und ein Flag des Ladevorgangs.
Öffnen Sie store.js
und beschreiben Sie den Anfangszustand der Anwendung und die erforderlichen Mutationen:
... 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 } });
Fügen Sie Aktionen hinzu, um Daten von der GitHub-API zu laden und die Suchabfrage zu ändern (wir benötigen sie für die Suchzeichenfolge). Infolgedessen wird unser Geschäft die folgende Form annehmen:
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); } } });
Suchzeichenfolge
Erstellen Sie eine neue Search.vue
Komponente im components
. Fügen Sie eine berechnete Eigenschaft hinzu, um die Komponente dem Speicher zuzuordnen. Wenn sich die Suchabfrage ändert, rufen wir die Suche mit Entprellen auf.
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>
Jetzt verbinden wir unsere App.vue
mit der Hauptkomponente von App.vue
und löschen gleichzeitig die vom Generator erstellten zusätzlichen Zeilen.
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>
Lassen Sie uns das Ergebnis im Browser sehen und sicherstellen, dass alles mit vue-devtools funktioniert:

Wie Sie sehen können, haben wir die gesamte Anwendungslogik bereit! Wir geben den Benutzernamen ein, die Anfrage wird ausgeführt und die Profildaten werden im Store gespeichert.
Benutzerprofil
Erstellen Sie die User.vue
Komponente und fügen Sie eine Logik hinzu, um die Last anzuzeigen, das Profil anzuzeigen und einen Fehler anzuzeigen, wenn der Benutzer nicht gefunden wird. Fügen Sie auch Übergangsanimationen hinzu.
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>
Verbinden Sie unsere Komponente in App.vue
und genießen Sie das Ergebnis:
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>

Tests
Wir werden einfache Tests für unsere Anwendung schreiben.
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'); }); });
Führen Sie die Tests mit dem Befehl aus
npm run test:e2e
Klicken Sie im folgenden Fenster auf die Schaltfläche Alle Spezifikationen ausführen und sehen Sie, ob die Tests bestanden wurden:

Montage
Vue CLI 3 unterstützt den neuen Anwendungserstellungsmodus, den modernen Modus. Er erstellt zwei Versionen von Skripten: Leichtgewicht für moderne Browser, die die neuesten JavaScript-Funktionen unterstützen, und eine Vollversion mit allen erforderlichen Polyphilen für ältere. Der Hauptcharme ist, dass wir uns absolut nicht um die Bereitstellung einer solchen Anwendung kümmern müssen. Es funktioniert einfach. Wenn der Browser <script type="module">
, wird der Lightweight-Build selbst aufgerufen. Wie das funktioniert, lesen Sie mehr in diesem Artikel .
Fügen Sie das package.json
im Befehl build hinzu:
"build": "vue-cli-service build --modern"
Ein Projekt zusammenstellen:
npm run build
Schauen wir uns die Größe der resultierenden Skripte an:
8.0K ./app-legacy.cb7436d4.js 8.0K ./app.b16ff4f7.js 116K ./chunk-vendors-legacy.1f6dfb2a.js 96K ./chunk-vendors.a98036c9.js
Wie Sie sehen können, reduziert die neue Methode die Größe der Baugruppe erheblich. Der Unterschied wird bei großen Projekten noch deutlicher, daher verdient die Funktion definitiv Aufmerksamkeit.
Code
Github
Demo
Das ist alles, danke fürs Zuschauen!