Zum Inhalt springen

Tutorial: NUXT.JS Application zur Darstellung aller Star Wars Filme – Teil #3

NUXT.JS

Content Area

Categories

Tutorial: NUXT.JS Application zur Darstellung aller Star Wars Filme – Teil #3

Update vom 27.09.2019:

  • Kleine Text-Korrekturen
  • Kleine inhaltliche Korrekturen
  • Vereinfachungen

Rückblick

Im zweiten Teil haben wir einen Blick auf das „Branching“ mit Git geworfen und uns die Gestaltungsmöglichkeiten von BootstrapVue etwas genauer angeschaut. In dem Kontext haben wir Components für den Sticky Footer sowie die Navigation angelegt und mit (zunächst) leeren Seiten verlinkt.

Im Anschluss haben wir die entsprechenden Seiten im ./pages Ordner angelegt und festgestellt, dass NUXT.JS das Routing automatisch für uns definiert.

Abschließend haben wir mit CSS noch Pagetransitions definiert und die aktive Seite im Menü gehighlightet.

Den Code aus der letzten Übung kannst du dir unter https://github.com/Thomas-A-Reinert/nuxtjs-tutorial-part-1/tree/teil_2 herunterladen.

WICHTIG! Der Code-Highlighter, den ich hier verwende, löscht automatisch „Trailing blank lines“, ESLint verlangt aber eine abschließende Leerzeile.

Füg am Ende also nach Möglichkeit immer eine Leerzeile ein!

Neuen Branch in Git einrichten

Wir gewöhnen uns an, für jeden neuen größeren Step einen eigenen Branch in Git anzulegen:

$ git checkout -b teil_3

Damit legen wir den neuen Branch „teil_3“ an und wechseln auch direkt dort hinein. Denk daran, dass du vorher alle Änderungen im zweiten Teil noch committen solltest!

Unterstützung für SCSS und Bootstrap-Variablen in NUXT.JS / BootstrapVue einrichten

Im letzten Kapitel haben wir bereits einige CSS-Styles festgelegt.

Das hat zwar funktioniert, aber ich finde SCSS eleganter. Zum Zweiten wäre es sinnvoll, direkt die Bootstrap-Variablen zu importieren und unsere eigenen Werte zu verwenden.

SCSS für NUXT.JS installieren

In Vue.js bzw. NUXT.JS können wir problemlos Pre-Processors wie Pug, CoffeeScript und Sass/SCSS für das <script> und das <style>-Tag verwenden – wir müssen dann nur angeben, was wir nutzen möchten. Siehe dazu auch die Doku.

Allerdings müssen wir dazu erst die nötigen Pakete installieren. Da wir nur SCSS verwenden möchten, reicht uns folgende Konsoleneingabe:

$ npm install --save-dev node-sass sass-loader

Danach können wir auch SCSS verwenden. Ein einfacher Test in ./layouts/default.vue :

<style lang="SCSS">
body {
 background-color: silver;
}
/* usw. .. */
</style>
Datei ./layouts/default.vue

Wenn keine Fehler in der Konsole generiert wurden und der Hintergrund hellgrau wurde, läuft alles korrekt. Die Deklaration für den body kannst du nun wieder entfernen – das diente nur zum Test.

Bootstrap-Variablen in NUXT.JS / BootstrapVue nutzen

Dazu legen wir eine neue Datei in ./assets/scss/bootstrap-variables.scss an

// Color system
$white: #fff !default;
$gray-100: #f8f9fa !default;
$gray-200: #e9ecef !default;
$gray-300: #dee2e6 !default;
$gray-400: #ced4da !default;
$gray-500: #adb5bd !default;
$gray-600: #6c757d !default;
$gray-700: #495057 !default;
$gray-800: #343a40 !default;
$gray-900: #212529 !default;
$black: #000 !default;

$blue: #007bff !default;
$indigo: #6610f2 !default;
$purple: #6f42c1 !default;
$pink: #e83e8c !default;
$red: #dc3545 !default;
$orange: #fd7e14 !default;
$yellow: #ffc107 !default;
$green: #28a745 !default;
$teal: #20c997 !default;
$cyan: #17a2b8 !default;

$colors: () !default;
// stylelint-disable-next-line scss/dollar-variable-default
$colors: map-merge(("blue": $blue,
    "indigo": $indigo,
    "purple": $purple,
    "pink": $pink,
    "red": $red,
    "orange": $orange,
    "yellow": $yellow,
    "green": $green,
    "teal": $teal,
    "cyan": $cyan,
    "white": $white,
    "gray": $gray-600,
    "gray-dark": $gray-800),
  $colors);

$primary: rgba(250, 255, 2, 1) !default; // "Star Wars Yellow"
$secondary: $gray-600 !default;
$success: $green !default;
$info: $cyan !default;
$warning: $yellow !default;
$danger: $red !default;
$light: $gray-100 !default;
$dark: $gray-800 !default;

$theme-colors: () !default;

$theme-colors: map-merge(("primary": $primary,
    "secondary": $secondary,
    "success": $success,
    "info": $info,
    "warning": $warning,
    "danger": $danger,
    "light": $light,
    "dark": $dark),
  $theme-colors);

$btn-outline-primary: rgb(139, 149, 0);
$green: rgba(43, 171, 14, 1);
$yellow: rgba(252, 199, 0, 1);
$orange: rgba(254, 124, 0, 1);
$red: rgba(174, 15, 11, 1);
$grey: rgba(0, 0, 0, .5);

$bg-medium: rgba(89, 98, 107, 1);
$col-medium: rgba(255, 255, 255, 1);

$dark-bg: rgba(52, 58, 64, 1);
$outline-dark: rgba(0, 0, 0, .25);
$dark-content: rgba(255, 255, 255, 1);

$light-bg: rgba(255, 255, 255, 1);
$light-content: rgba(89, 98, 107, 1);

$card-bg: rgba(255, 255, 255, 0.9);

$card-header-bg: rgba(52, 58, 64, .5);
$card-header-content: rgba(255, 255, 255, .9);

$header-bg-color: $grey;
$header-bg-input: rgba(0, 0, 0, 0.9);
$input-placeholder: rgba(255, 255, 255, .5);

$code-bg: rgb(225, 225, 225);
Datei ./assets/scss/bootstrap-variables.scss

Ich habe hier die Standards importiert und nur die Primary-Color (Zeile 42) auf das „Star Wars Gelb“ geändert. Ob und was wir irgendwann noch ändern, sehen wir später.

Nun müssen wir in allen Dateien, in denen wir unsere eigenen Variablen nutzen möchten, noch unsere eigenen Variablen, die Start-SCSS aus dem dem Bootstrap-NPM-Paket und die aus dem BootstrapVue-Paket importieren.

Der <style>-Bereich in der ./layouts/default.vue sieht damit wie folgt aus:

<style lang="SCSS">
@import '~assets/scss/bootstrap-variables.scss';
@import '~bootstrap/scss/bootstrap.scss';
@import '~bootstrap-vue/src/index.scss';

body {
  padding-top: 100px;
  padding-bottom: 100px;
}

#header-logo {
  max-height: 2rem;
  margin-right: 1.5rem;
}

.nuxt-link-exact-active {
  color: $primary !important;
}

.page-enter-active,
.page-leave-active {
  transition: opacity 0.5s;
}

.page-enter,
.page-leave-to {
  opacity: 0;
}
</style>
Datei: ./layouts/default.vue

Um zu prüfen, ob alles funktioniert, habe ich in Zeile 17 die Farbe des aktiven Navigationspunkts in unsere neue $primary-Color geändert. Das #header-logo spielt gleich eine Rolle.

Bei einem Reload sollte die Navigation in „Home“ nun so aussehen:

Star Wars Films - SCSS Navigation
Star Wars Films – SCSS Navigation

Dateien aus dem ./assets-Folder einbinden

Wir haben bereits die SCSS-Variablen im Assets-Ordner zugegriffen, dabei aber gar nicht angesprochen, worin eigentlich die Vorteile liegen und was wir dort überhaupt ablegen sollen.

Siehe dazu auch die Doku von NUXT.JS.

Einerseits sollte alles im ./assets-Ordner landen, was generiert wird – wie zum Beispiel unser SCSS. Daraus wird schließlich CSS generiert, das dann automatisch in unsere Anwendung eingebunden wird.

Der größte Vorteil besteht allerdings im „Asset-Serving“ von NUXT mittels webpack.

Dazu nutzt NUXT.JS den file-loader und url-loader von webpack, wobei der file-loader dazu da ist die Pfade korrekt aufzulösen und optimales Caching zu ermöglichen.

Noch interessanter ist allerdings der url-loader, der uns ermöglicht Dateien unter einer definierbaren Größe inline im generierten HTML bzw. Script zu laden. Damit verzichten wir auf unnötige Requests. Die Standard-Größe beträgt dabei 1kB.

Wenn du darauf verzichten möchtest, kannst du deine Daten auch im ./static-Ordner ablegen.

Hinzufügen des Stars Wars Logos

Wir wollen in der Navigation als „Brand-Image“ das Star Wars Logo einbinden. Dazu „klauen“ wir uns von Wikipedia für die Übung das Star Wars Logo als SVG und speichern es im Ordner ./assets/imgs/ . Das ist zwar mit 31kB viel zu groß und vom url-loader können wir dabei auch nicht profitieren, aber SVG-Optimierung soll hier nicht unser Thema sein..

Anschließend binden wir es in die ./components/Navigation.vue ein und ändern dabei nur den <b-navbar-brand>-Block wie folgt ab:

<b-navbar-brand to="/" class="d-flex align-items-center">
  <img
    id="header-logo"
    src="~assets/imgs/SW_opening_crawl_logo.svg"
    alt="NUXT.JS – Star Wars Films"
  />
  <h1 class="h4">Star Wars Films</h1>
</b-navbar-brand>
Datei: ./components/Navigation.vue

Alle Dateien im ./assets-Ordner sprechen wir mit dem Prefix „~assets/“ an, danach folgt die vorgesehene Ordnerstruktur wie üblich.

Da ich im SCSS für die default.vue bereits eine max-height: 2rem und einen Margin nach rechts festgelegt hatte (siehe oben), sollte die Navigation nun so aussehen:

Star Wars Films - Navigation mit Logo
Star Wars Films – Navigation mit Logo

Star Wars-Styling: Feinschliff

Da das Prinzip jetzt klar sein sollte, möchte ich dem Ganzen zur Festigung noch den letzten Schliff verpassen, damit die App auch das Star Wars Look & Feel bekommt.

Für die Funktionalität ist das komplett unnötig – wer möchte, springt also direkt zu Kapitel #4 und lädt sich dort die Source-Files aus dieser Übung herunter.

Star Wars Font konvertieren und einbinden

Im Web gibt es zahlreiche Star Wars Fonts – ich nutze für unsere Übung den Font starjedi von „Boba Fonts“ (in ./starjedi/Starjedi.ttf), den du von dafont.com herunterladen kannst. Den gibt es allerdings nur als .ttf File, deshalb müssen wir ihn mit FontSquirrel in einen Webfont konvertieren.

Die beiden Woff-Dateien, die ich erhalte, speichere ich unter ./assets/fonts/ . Nun müssen wir sie nur noch im (S)CSS einbinden. Ich öffne die ./assets/scss/bootstrap-variables.scss und füge direkt am Anfang folgenden Code ein:

@font-face {
  font-family: 'Star Wars';
  src: url('~assets/fonts/starjedi-webfont.woff2') format('woff2'),
    url('~assets/fonts/starjedi-webfont.woff') format('woff');
  font-weight: normal;
  font-style: normal;
  font-display: swap;
}
Datei: ./assets/scss/bootstrap-variables.scss

Beachte hier die Zeilen 3-4 – auch hier müssen wir wieder den Assets-Ordner korrekt referenzieren.

Anschließend müssen wir die Schrift noch auf die Seiten anwenden. Dabei räume ich gleichzeitig ein wenig auf.

  • Das NUXT-Logo aus der ./pages/index.vue rausschmeißen und Referenzen (im Script-Bereich) dazu aufheben.
  • Dunkler Hintergrund und „Glow“ um die Headline-Schrift.
  • Alles S/CSS aus den Components und Seiten entfernen und zentral in der ./layouts/default.vue unterbringen.

Damit sieht meine komplette ./layouts/default.vue nun wie folgt aus:

<template>
  <div>
    <Navigation />
    <nuxt />
    <Footer />
  </div>
</template>

<script>
import Navigation from '~/components/Navigation'
import Footer from '~/components/Footer'

export default {
  components: {
    Navigation,
    Footer
  }
}
</script>

<style lang="SCSS">
@import '~assets/scss/bootstrap-variables.scss';
@import '~bootstrap/scss/bootstrap.scss';
@import '~bootstrap-vue/src/index.scss';

body {
  padding-top: 100px;
  padding-bottom: 100px;
  background-color: $black;
  color: $light;
}

.navbar-brand {

  #header-logo {
    max-height: 2rem;
    margin-right: 1.5rem;
  }

  h1 {
    font-family: "Star Wars", Arial, Helvetica, sans-serif;
    font-size: 1.25rem;
  }
}

.container {
  min-height: calc(100vh - 3rem - (1.25rem + 3.25rem + 1rem) -200px;
  /* Berechnung: Viewport-Höhe - <Footer> - <Navigation> - <body>-Padding */
  text-align: center;
}

.title {
  font-family: "Star Wars", Arial, Helvetica, sans-serif;
  font-weight: normal;
  font-size: 3rem;
  color: $dark;
  text-shadow:  0px 0px 3px transparentize($primary, 0.5),
                -1px 1px 3px transparentize($primary, 0.5),
                1px -1px 3px transparentize($primary, 0.5),
                -1px -1px 3px transparentize($primary, 0.5);
}

.subtitle {
  font-weight: 300;
  font-size: 2.5rem;
}

.nuxt-link-exact-active {
  color: $primary !important;
}

.page-enter-active,
.page-leave-active {
  transition: opacity 0.5s;
}

.page-enter,
.page-leave-to {
  opacity: 0;
}
</style>
Datei: ./layouts/default.vue

Ergebnis

Damit sieht unsere Anwendung jetzt schon wesentlich besser aus – „Welcome to the Dark Side“ 😉

Star Wars Films – Abschluss Kapitel 3
Star Wars Films – Abschluss Kapitel 3

Falls es bei dir anders ausschaut, sieh noch einmal genau nach, ob du Logo, den Link-Bereich und das CSS in der ./pages/index.vue entfernt hast.

Hausaufgabe

  • Speichere den aktuellen Stand als Git-Commit.
  • Pass das Layout an deine eigenen Wünsche an!
  • Schau dir an, welche Möglichkeiten die „The Star Wars API“ bietet (Siehe Vorschau).

Vorschau

In Kapitel #4 gehen wir inhaltlich wieder ans Eingemachte.

Hier wollen wir unter Zuhilfenahme von Axios Requests an die REST-API-Schnittstelle der „The Star Wars API“ stellen und die JSON-Daten in unsere Anwendung einbinden.

To top of Page