In diesem Beispiel wird eine Website mit Node.js erstellt, um ein logisches Websiteverhalten bereitzustellen. Mithilfe des Express.js-Frameworks wird die Website als Webanwendung implementiert, mit logischem Routing zu anderen Abschnitten der Website.
HTML und CSS basieren auf unserem responsiven Website-Design mit CSS Grid und Flexbox. Der HTML-Code wird als Vorlage umgestaltet, sodass der Layoutcode beim Hinzufügen neuer Seiten wiederverwendet werden kann.
Knoten installieren
Node.js, auch Node genannt, ist eine Laufzeitumgebung zum Schreiben serverseitiger Anwendungen in JavaScript.
Wenn Node bereits auf Ihrem Computer installiert ist, können Sie diesen Abschnitt überspringen und mit der Erstellung einer neuen Express-App fortfahren.
Laden Sie das Node-Installationsprogramm von der offiziellen Node.js-Download-Website herunter. Wählen Sie die LTS-Version (Long Term Support) für Ihr Betriebssystem.
Windows und macOS
Öffnen Sie das Node-Installationsprogramm und führen Sie es aus (.msi unter Windows, .pkg unter macOS).
Aktivieren Sie unter Windows auf dem Installationsbildschirm mit der Bezeichnung Tools for Native Modules das Kontrollkästchen Notwendige Tools automatisch installieren.
Linux
Auf Linux-Systemen können Sie Node mit Ihrem Paketmanager installieren, die kompilierten Binärdateien manuell installieren oder Node aus der Quelle erstellen. Ausführliche Informationen finden Sie im offiziellen Installations-Wiki von Node.js.
Alle Betriebssysteme
Öffnen Sie nach Abschluss der Installation ein Terminal- oder Eingabeaufforderungsfenster. Führen Sie den folgenden Befehl aus, um npm, den Node-Paketmanager, zu aktualisieren. Der Schalter -g (global) gibt an, dass die Software systemweit installiert wird, nicht nur die aktuelle Node-App.
Windows
npm install -g npm
Linux und macOS
sudo npm install -g npm
Verwenden Sie schließlich npm, um die Express-Generator-Anwendung global zu installieren.
Windows
npm install -g express-generator
Linux und macOS
sudo npm install -g express-generator
Erstellen Sie eine neue Express-App
Generieren Sie in einem Terminal- oder Eingabeaufforderungsfenster eine neue Express.js-App. In unserem Beispiel lautet der App-Name myapp, und die Ansichts-Engine ist als pug angegeben.
express myapp --view="pug"
Wechseln Sie in das Verzeichnis der neuen Express-App.
cd myapp
Verwenden Sie im Express-App-Verzeichnis npm install, um die erforderlichen Abhängigkeiten herunterzuladen und zu installieren, wie in der Datei „package.json“ aufgeführt.
npm install
Wenn Sicherheitsupdates für die installierten Abhängigkeiten verfügbar sind, wird eine Benachrichtigung angezeigt.
found 1 low severity vulnerability run `npm audit fix` to fix them, or `npm audit` for details
Wenden Sie in diesem Fall die Sicherheitsupdates an.
npm audit fix
nodemon installieren
Installieren Sie im Verzeichnis der Express-App nodemon. Die Option –save-dev gibt an, dass nodemon eine Entwicklungsabhängigkeit ist. Es wird nicht in der Anwendung selbst verwendet, sondern ist ein Werkzeug, das während der Entwicklung verwendet wird.
npm install --save-dev nodemon
Fügen Sie ein Startskript für die Entwicklung hinzu
Ein Startskript für die Entwicklung bietet eine Möglichkeit, Ihre Webanwendung mit Optionen zu starten, die Ihnen bei der Entwicklung der App helfen, z. B. ausführliche Fehlermeldungen.
Öffnen Sie in einem Texteditor die Datei package.json im App-Verzeichnis. Diese JSON-Datei gibt die Abhängigkeiten an, die von Ihrer Node-App verwendet werden. Darüber hinaus enthält es benannte Startskripts, die die Anwendung auf unterschiedliche Weise starten.
Suchen Sie in package.json den Eintrag „scripts“. Standardmäßig enthält es nur ein Skript (“Start”).
"scripts": { "start": "node ./bin/www" },
Fügen Sie eine neue Zeile hinzu, die ein Skript devstart wie folgt definiert.
Linux und macOS
"scripts": { "start": "node ./bin/www", "devstart": "DEBUG=myapp:* nodemon ./bin/www" },
Windows
"scripts": { "start": "node ./bin/www", "devstart": "SET DEBUG=myapp:* & nodemon ./bin/www" },
Diese Skripte (“start” und “devstart”) können durch Ausführen des Befehls npm run scriptname ausgeführt werden.
Der Befehl npm run devstart startet die App mit zwei zusätzlichen aktivierten Entwicklungsfunktionen.
- Die Umgebungsvariable DEBUG wird gesetzt und gibt an, dass die Protokoll- und Fehlerseiten der Konsole, wie z. B. HTTP 404, zusätzliche Informationen wie einen Stack-Trace anzeigen.
- Darüber hinaus überwacht nodemon bestimmte wichtige Website-Dateien. Wenn Sie diese Dateien ändern, z. B. eine Seite neu gestalten oder statische Inhalte ändern, startet nodemon den Server automatisch neu, um die Änderungen widerzuspiegeln.
Starten Sie den Webserver im Entwicklungsmodus.
npm run devstart
Wenn die Windows-Firewall die Webserveranwendung blockiert, klicken Sie auf Zugriff zulassen.
Vorschau der Web-App
Wenn die Anwendung ausgeführt wird, fungiert Ihr Computer als Webserver und stellt HTTP auf Port 3000 bereit.
Um eine Vorschau der Website anzuzeigen, öffnen Sie einen Webbrowser mit der Adresse localhost:3000.
Jedes mit Ihrem lokalen Netzwerk verbundene Gerät kann die Anwendung unter der Adresse IP-Adresse: 3000 anzeigen, wobei IP-Adresse die lokale IP-Adresse des Computers ist, auf dem die App ausgeführt wird.
Wenn Sie sich nicht sicher sind, wie die lokale IP-Adresse des Computers lautet, lesen Sie: So finden Sie meine IP-Adresse.
Um eine Vorschau der Website auf einem mobilen Gerät anzuzeigen, verbinden Sie das WLAN mit Ihrem lokalen Netzwerk und öffnen Sie die Adresse in einem Browser.
HTML-Vorlagen
Unser Beispiel verwendet CSS, JavaScript und HTML aus der Anleitung zum Erstellen einer responsiven Website mit CSS Grid und Flexbox. CSS und JavaScript werden wörtlich verwendet. Der HTML-Code wird in eine Templating-Sprache umgestaltet.
Unter Verwendung einer Vorlagensprache wird der Layoutcode nur einmal geschrieben und von anderen Seiten geerbt.
Die Software, die eine Vorlage in ihr endgültiges Format konvertiert, wird als Vorlagenprozessor bezeichnet. Im Zusammenhang mit HTML wird ein Vorlagenprozessor als Ansichtsmaschine bezeichnet.
Express.js unterstützt mehrere Ansichtsmodule, einschließlich Pug.
Überblick über Mops
Die Pug-Sprache beschreibt HTML-Dokumente auf eine Weise, die Vorteile und zusätzliche Funktionen bietet. Pug-Dateien werden in HTML gerendert, wenn der Benutzer sie anfordert.
Die Sprachsyntax von Pug beseitigt die Notwendigkeit, Tags zu schließen oder in Klammern einzuschließen. Es unterstützt auch geerbte Vorlagen, Iterationen, Bedingungen und JavaScript-Evaluierung.
Beispiel für eine HTML-zu-Pug-Konvertierung
Dies sind die ersten Zeilen des HTML-Codes zum Erstellen einer responsiven Website mit CSS Grid und Flexbox.
<!DOCTYPE html> <html lang="en"> <head> <meta name="viewport" content="width=device-width, initial-scale=1"> <meta charset="utf-8"> <title>Title</title> <link rel="stylesheet" href="index.css"> <script src="index.js"></script> </head> <body> <div id="menu"> <section id="menuitems"> <div class="menubutton"> <h1 onclick="menuToggle('hide')" class="menubutton">☰</h1>
In Pug kann das gleiche HTML so geschrieben werden.
doctype html html head meta(name="viewport" content="width=device-width, initial-scale=1") meta(charset="utf-8") title Title link(rel="stylesheet", href="index.css") script(src="index.js") body #menu section#menuitems .menubutton h1.menubutton(onclick="menuToggle('hide')") ☰
Element-Tags werden ohne Klammern geschrieben. Untergeordnete Elemente werden eingerückt. Die Ebene der Einrückung bestimmt den Umfang eines Elements, daher sind schließende Tags nicht erforderlich.
Die CSS-Selektoren „id“ und „class“ können als element#id, element.class, element#id.class usw. geschrieben werden. Wenn kein Element angegeben ist, wird davon ausgegangen, dass das Element ein div ist. Beispielsweise kann
Nach dem Elementnamen und seinen Selektoren können Attribute in Klammern als kommagetrennte Liste angegeben werden. Zum Beispiel:
HTML
<div class="button" onmouseover="glow()" onclick="start()">
Mops
.button(onmouseover="glow()", onclick="start()")
Mehrere Elemente in einer Zeile auflisten
Wenn auf das Element ein Doppelpunkt (:) folgt, kann darauf ein untergeordnetes Element in derselben Zeile folgen. Die folgenden zwei Abschnitte von Pug erzeugen dieselbe HTML-Ausgabe.
a(href="/home") p Home
a(href="https://www.computerhope.com/home"): p Home
Beides wird im folgenden HTML gerendert.
<a href="https://www.computerhope.com/home"><p>Home</p></a>
Auswertung von JavaScript
Wenn dem Element ein Gleichheitszeichen (=) folgt, wird alles, was in dieser Zeile folgt, als gepufferter Code interpretiert. Der Code wird als JavaScript ausgewertet und die Ausgabe „gepuffert“ (als Inhalt des Elements aufgenommen). In seiner einfachsten Form kann gepufferter Code der Name einer Variablen sein, die von der Anwendung übergeben wird.
Beispielsweise übergibt der App-Router für die Homepage, index.js, die Variable title mit dem Wert „Our Farm Stand“ an die Methode express.Router(), die sie an Pug weitergibt. Wenn Pug layout.pug rendert, die folgende Zeile:
title= pagetitle
…wird interpretiert als:
title Our Farm Stand
… was als folgender HTML-Code gerendert wird:
<title>Our Farm Stand</title>
Vorlagenvererbung
Pug-Dokumente können andere Pug-Dokumente mit den Schlüsselwörtern extend und block erben.
Sie können beispielsweise ein grundlegendes Website-Layout, layout.pug, mit gemeinsam genutzten Elementen der Seite erstellen.
doctype html html head title Page Title body p Content block foo
Die Block-foo-Anweisung lautet: „Fügen Sie hier einen Inhaltsblock mit dem Namen foo ein, der in einem anderen Pug-Dokument angegeben ist, das diese Vorlage erbt.“
Dokumente, die layout.pug erben, müssen mit der Anweisung „extensions layout“ beginnen und auf der obersten Einzugsebene (am Anfang einer neuen Zeile) eine block foo-Anweisung enthalten. Die Kinder dieser “block foo”-Anweisung werden in die Vorlage an der Stelle des entsprechenden Blocks eingefügt.
Ein Pug-Dokument kann layout.pug wie folgt erben.
extends layout block foo p This is the home page.
Wenn das Dokument gerendert wird, lädt die Pug-Engine die Datei layout.pug. Der Zeilenblock foo in layout.pug wird durch p ersetzt. Dies ist die Startseite.
Überblick über die standardmäßige Express-App
Die Standardstruktur der Express-App ist hier aufgelistet, mit Beschreibungen jeder Datei und jedes Verzeichnisses.
myapp/ (Contains the entire Express app) ├─ app.js The core logic of the Express app. ├─ bin/ (Contains the app's executable scripts) │ └─ www A wrapper that runs app.js. ├─ node_modules/ (Contains dependencies installed by npm) ├─ package-lock.json JSON manifest of installed dependencies. ├─ package.json JSON of dependencies and config specific to your app. ├─ public/ (Files downloaded by the user's web browser) │ ├─ images/ (Contains client-accessible image files) │ ├─ javascripts/ (Contains client-accessible JavaScript files) │ └─ stylesheets/ (Contains client-accessible CSS) │ └─ style.css The site's CSS stylesheet. ├─ routes/ (Contains logic for individual site routes) │ ├─ index.js Logic of the "index" route (/). │ └─ users.js Logic of the "users" route (/users). └─ views/ (Contains HTML templates) ├─ error.pug View displayed for error pages, such as HTML 404. ├─ index.pug View displayed for the site root (/). └─ layout.pug View template of layout shared by all pages.
Die Kernfunktionalität der Website ist in app.js definiert. Routen werden in dieser Datei benannt und spezifiziert.
Eine Route ist eine Seite oder ein Abschnitt der Website mit einem eindeutigen Pfad in der URL, z. B. www.example.com/search, www.example.com/login usw. Diese Routen sind benannt und mit Routenlogik-Skripts verknüpft. in app.js.
Routenlogikskripte werden im Routenordner gespeichert. Wenn ein Benutzer eine Route anfordert, verarbeitet sein Routenlogikskript die HTTP-Anforderungsdaten und sendet eine Antwort.
Der Views-Ordner enthält die HTML-Vorlagen, Views genannt, die von der View-Engine (Pug) verarbeitet werden.
Implementierung: JavaScript, CSS und Pug
Der folgende Code implementiert die Express-Web-App.
App-Dateistruktur
myapp/ ├─ app.js App core logic ├─ bin/ │ └─ www ├─ node_modules/ ├─ package-lock.json ├─ package.json ├─ public/ │ ├─ images/ │ ├─ javascripts/ │ │ └─ menu.js Implements menu toggle │ └─ stylesheets/ │ └─ style.css Stylesheet ├─ routes/ │ ├─ about.js Logic for route /about │ ├─ advice.js Logic for route /advice │ ├─ contact.js Logic for route /contact │ ├─ index.js Logic for route / │ ├─ recipes.js Logic for route /recipes │ ├─ tips.js Logic for route /tips │ └─ users.js Not used, can be deleted └─ views/ ├─ about.pug View for route /about ├─ advice.pug View for route /advice ├─ contact.pug View for route /contact ├─ error.pug ├─ index.pug View for route / ├─ layout.pug View template shared by all pages ├─ recipes.pug View for route /recipes └─ tips.pug View for route /tips blue = modified, green = new, red = not used
meineapp/app.js
Die Kern-App-Logik ist im Wesentlichen dieselbe wie die standardmäßige Express-App, wobei zusätzliche Routen definiert sind. Die Route “users” wird entfernt.
// core dependencies var createError = require('http-errors'); var express = require('express'); var path = require('path'); var cookieParser = require('cookie-parser'); var logger = require('morgan'); // create route objectsvar indexRouter = require('./routes/index');var aboutRouter = require('./routes/about');var contactRouter = require('./routes/contact');var tipsRouter = require('./routes/tips');var recipesRouter = require('./routes/recipes');var adviceRouter = require('./routes/advice'); // the app object var app = express(); // view engine setup app.set('views', path.join(__dirname, 'views')); app.set('view engine', 'pug'); // app config app.use(logger('dev')); app.use(express.json()); app.use(express.urlencoded({ extended: false })); app.use(cookieParser()); app.use(express.static(path.join(__dirname, 'public'))); // tell the app to use these routesapp.use("https://www.computerhope.com/", indexRouter);app.use('/about', aboutRouter);app.use('/contact', contactRouter);app.use('/tips', tipsRouter);app.use('/recipes', recipesRouter);app.use('/advice', adviceRouter); // catch 404 and forward to error handler app.use(function(req, res, next) { next(createError(404)); }); // error handler app.use(function(err, req, res, next) { // set locals, only providing error in development res.locals.message = err.message; res.locals.error = req.app.get('env') === 'development' ? err : {}; // render the error page res.status(err.status || 500); res.render('error'); }); // expose this app to scripts that require it, i.e. myapp/bin/www module.exports = app;
meineapp/routes/layout.pug
Die Datei layout.pug enthält das Kernlayout der Seite, das von allen Seiten der Website gemeinsam genutzt wird. Es enthält alles, was zum Anzeigen einer Seite erforderlich ist, mit Ausnahme des Haupttextinhalts (Block Haupttext).
doctype html html head title= pagetitle meta(charset="utf-8") meta(name="viewport" content="width=device-width, initial-scale=1") script(src="/javascripts/menu.js") link(rel="stylesheet", href="/stylesheets/style.css") body #menu section#menuitems .menubutton h1.menubutton(onclick="menuToggle('hide')") ☰ a(href="/") h3.menuhead Our Farm Stand a(href="/tips") h3.sectrule Tips for living well a(href="/recipes") h3 Recipes a(href="/advice") h3 Homesteading advice a(href="/about") h3.sectrule About Us a(href="/contact") h3 Contact Us #container #header a(href="/") h1.logo Our Farm Stand .headspace h1.menubutton(onclick="menuToggle('show')") ☰ h1.placeholder ☰ h2.navitem a(href="/about") .clickable-area About Us h2.navitem a(href="/contact") .clickable-area Contact Us #panel.left section#sections .sectionlink a(href="/tips") .clickable-area Tips for living well .sectionlink a(href="/recipes") .clickable-area Recipes .sectionlink a(href="/advice") .clickable-area Homesteading advice block mainbody #panel.right h3 Our friends section#partners.tall .partnerlink a(href="/") .clickable-area Green Valley Greens .partnerlink a(href="/") .clickable-area Turkey Hill Farm .partnerlink a(href="/") .clickable-area Burt's Maple Syrup .partnerlink a(href="/") .clickable-area Only Organic Seeds #footer p Copyright © 2020 Alice & Bob's Farm Stand
myapp/views/index.pug
Die Datei index.pug erweitert layout.pug und enthält Hauptinhalt für die Route /.
extends layout block mainbody #mainbody section.mainbodyitems h3 Announcements section.announcements .announceitem h4.title Open for business p.date Jan. 15 p Renovations of our new storefront are complete, and we're open for business. h3 Items for sale section.forsaleitems table tr th Item th Description th Price th.qty Qty tr td Milk td Good source of calcium. td.price $2 span.perunit / half gal. td.qty 3 tr td Eggs td Great for breakfast and baking. td.price $4 span.perunit / doz. td.qty 6 tr td Whole chicken td Perfect for roasting. td.price $5 span.perunit / lb. td.qty 4 h3 Upcoming events section .eventitem h4.title Cider Fest p.date October 20, 2pm–6pm p Celebrate the season with fresh-pressed cider from our orchards. .eventitem h4.title Bread baking workshop p.date December 13, 9am–noon p Learn how to create and cultivate a sourdough starter. h3 Message of the day section .motditem p Eat better food. Support your local farm stand. h3#partners.wide Our friends section#partners.wide .partnerlink.wide a(href="") .clickable-area Green Valley Greens .partnerlink.wide a(href="") .clickable-area Turkey Hill Farm .partnerlink.wide a(href="/") .clickable-area Burt's Maple Syrup .partnerlink.wide a(href="") .clickable-area Only Organic Seeds .bodyspace
meineapp/routes/index.js
Die Datei index.js enthält Logik für die Route /.
var express = require('express'); var router = express.Router(); router.get("https://www.computerhope.com/", function(req, res, next) { res.render('index', { pagetitle: 'Our Farm Stand' }); }); module.exports = router;
myapp/public/javascripts/menu.js
Die Datei menu.js enthält das JavaScript aus dem Grid- und Flexbox-Beispiel. Es implementiert die Menüumschaltfunktion.
function menuToggle(state) { var ele = document.getElementById('menu'); switch(state) { case 'show': ele.style.opacity=1; ele.style.color="rgb(96, 96, 96)"; ele.style.visibility='visible'; ele.style.transition='visibility 0s, opacity 0.3s'; break; case 'hide': ele.style.opacity=0; ele.style.color="black"; ele.style.visibility='hidden'; ele.style.transition='visibility 0.3s, opacity 0.3s'; break; } }
meineapp/public/stylesheets/style.css
Die Datei style.css enthält das CSS aus dem Grid- und Flexbox-Beispiel.
/* element styles */ * { margin: 0; /* by default, all elements (selector *) have no margin */ } html { width: 100%; /* 100% width of parent (root) element */ height: 100vh; /* 100% height of viewport */ background: rgb(0, 0, 0, 0.1); /* 10% black */ font-size: 1.0em; /* our root font size */ font-family: Arial, Helvetica, sans-serif; /* default font */ } body { min-height: 100%; } section { padding: 0.5rem; flex-grow: 1; /* in a flexbox, sections expand along flex axis */ } h1 { /* Website name in header */ font-size: 2.0rem; font-weight: normal; } h2 { /* About, Contact */ font-size: 1.25rem; } h3 { /* Section headings */ font-size: 1.2rem; padding: 0.5rem; } h4 { /* Section item title */ font-weight: normal; padding: 0.5rem; } p { /* Section item body */ padding: 0.5rem; } a:link, a:visited { /* anchor links, and visited anchor links */ color: black; text-decoration: none; /* disable underline */ } a:hover { /* when anchor link is hovered */ color: rgb(25, 25, 25); } a:active { /* when anchor link is clicked */ color: rgb(96, 96, 96); } /* component styles */ #container { display: grid; height: 100vh; grid-template-columns: [left] 10rem auto 10rem [right]; grid-template-rows: [top] 5rem auto 5rem [bottom]; /* header height fits its content */ grid-template-areas: "head head head" "panleft mainbody panright" "foot foot foot"; } #header { grid-area: head; /* corresponds to name in template */ background: rgb(0, 0, 0, 0.2); /* 20% black */ display: flex; flex-direction: row; justify-content: space-between; align-items: baseline; /* site name and nav item text aligns baseline */ padding: 1.0rem; } #panel { /* for element id="panel" */ display: flex; /* this element is a flexbox parent */ flex-direction: column; /* its child elements flex vertically */ padding: 0.5rem; background: rgb(0, 0, 0, 0.1); /* 10% black */ } #panel.left { /* for element id="panel" and class="left" */ grid-area: panleft; /* this element fills a grid area */ } #panel.right { grid-area: panright; } #footer { grid-area: foot; display: flex; /* this element is a flexbox parent */ flex-direction: column; /* its child elements flex vertically */ justify-content: center; /* horizontal center footer content */ align-items: center; /* vertical center footer content */ padding: 0.5rem; background: rgb(0, 0, 0, 0.2); } #mainbody { /* for element id="mainbody" */ display: flex; /* this element is a flexbox parent */ flex-direction: column; /* its child elements flex vertically */ grid-area: mainbody; justify-self: center; /* fixed-width mainbody always centered */ width: 100%; min-width: 22.5rem; /* mainbody width can't go < 22.5rem */ } div#panel, div#mainbody { /* extra space under header */ padding-top: 0.5rem; } #partners, #sections { /* for element id="partners" or id="sections" */ display: flex; /* this element is a flexbox parent */ flex-direction: row; /* its child elements flex horizontally */ flex-wrap: wrap; /* its child elements can wrap to next line */ align-content: flex-start; /* child elements start in upper left */ } #partners.wide { /* for element id="partners" and class="wide" */ display: none; /* by default, do not display this element */ } #menu { position: absolute; /* menu position unaffected by other elements */ right: 0; /* zero pixels from the right boundary */ background: rgb(239, 239, 239); border: 0.15rem solid rgb(0, 0, 0, 0.4); visibility: hidden; /* visibility property supports transitions */ opacity: 0; /* opacity + visibility transition = menu fade effect */ z-index: 1; /* ensure menu appears over all other content */ } #menuitems { /* menu is implemented as a flexbox container */ display: flex; flex-direction: column; padding: 1rem; } #menuitems h3 { border-top: 0.15rem solid rgb(0, 0, 0, 0.1); /* light horizontal rule */ } #menuitems .sectrule { border-color: rgb(0, 0, 0, 0.25); /* darker horizontal rule */ } #menuitems .menuhead { border-top: none; } #menuitems h3:hover { background-color: rgb(0, 0, 0, 0.1); /* gray of rollover menuitems */ } .menubutton { text-align: right; cursor: pointer; /* indicates it can be clicked like a link */ user-select: none; /* user cannot select the button as text */ } #menuitems .alignright { text-align: right; /* right-aligned menu item text (unused) */ } #header h1.menubutton { display: none; /* in default view (landscape), hide menu button */ border: 0.15rem solid rgb(0, 0, 0, 0); /* (invisible) alignment shim */ } #header .placeholder { /* this invisible button is rendered when menu */ color: rgb(0, 0, 0, 0); /* button is hidden, so header height matches. */ user-select: none; /* user can't select text of invisible button */ } .sectionlink, .partnerlink { border-radius: 0.25rem; /* give this element a slight rounded edge */ font-weight: normal; font-size: 1.1rem; padding: 0.5rem; width: 7rem; /* fixed width for these items */ margin-bottom: 1rem; /* slight margin for readability */ background: rgb(0, 0, 0, 0.1); } .sectionlink:hover, .partnerlink:hover { background-color: rgb(0, 0, 0, 0.065); /* brighten bg on mouse hover */ } .partnerlink { height: 7rem; /* partner elements are additionally fixed height */ } .partnerlink.wide { margin: 0.5rem 1rem 0.5rem 0; /* margins for spacing if they wrap */ } .clickable-area { /* use whenever a clickable area excludes margins */ height: 100%; /* clickable area spans height of parent */ } .eventitem, .announceitem, .motditem { margin-bottom: 0.5rem; /* slight margin for readability */ } .title { /* e.g., "Open for business" */ font-style: italic; font-weight: normal; font-size: 1.1rem; } .date, .ingredient { /* e.g., January 1, 2021 */ font-style: italic; font-size: 0.9rem; padding: 0 0 0.01rem 0.5rem; color: rgb(0, 0, 0, 0.5); } .navitem { /* About, Contact */ font-weight: normal; padding: 0 0.5rem 0 1rem; } .headspace, .panspace, .footspace, .bodyspace { flex-grow: 1; /* these elements expand on flex axis to fill space */ } /* table styles ("items for sale") */ table { border-collapse: collapse; /* pixel-adjacent table cells */ width: 100%; margin-bottom: 1rem; } th { text-align: left; } tr { margin: 4rem 0 0 0; border-bottom: 0.15rem solid rgb(0, 0, 0, 0.2); /* horizontal rule */ } td, th { padding: 0.5rem; vertical-align: top; } td.price { white-space: nowrap; /* white space in price does not wrap line */ } td.qty, th.qty { text-align: center; } span.perunit { opacity: 0.5; } /* responsive styles applied in portrait mode */ @media screen and (max-width: 45rem) { /* if viewport width < 45rem */ #panel.left { grid-column-end: left; /* panel grid area shrinks to nothing */ } #panel.right { grid-column-start: right; /* panel grid area shrinks to nothing */ } #partners.tall { display: none; /* hide partners in panel (overwrites display: flex) */ } #partners.wide { display: flex; /* show partners in body (overwrites display: none) */ } #panel, /* these disappear from layout */ #header .placeholder, .navitem { display: none; } #mainbody { grid-column-start: left; /* mainbody now starts at left edge */ grid-column-end: right; /* mainbody now ends at right edge */ } #header h1.menubutton { /* display the header menu button */ display: inline; /* overwrites display: none */ } }
Nebenwege
Die folgenden Dateien enthalten die Logik für sekundäre Routen – About, Advice, Contact usw.
meineapp/routes/about.js
var express = require('express'); var router = express.Router(); router.get("https://www.computerhope.com/", function(req, res, next) { res.render('about', { pagetitle: 'About Us' }); }); module.exports = router;
myapp/routes/advice.js
var express = require('express'); var router = express.Router(); router.get("https://www.computerhope.com/", function(req, res, next) { res.render('advice', { pagetitle: 'Homesteading Advice' }); }); module.exports = router;
meineapp/routes/contact.js
var express = require('express'); var router = express.Router(); router.get("https://www.computerhope.com/", function(req, res, next) { res.render('contact', { pagetitle: 'Contact Us' }); }); module.exports = router;
myapp/routes/recipes.js
var express = require('express'); var router = express.Router(); router.get("https://www.computerhope.com/", function(req, res, next) { res.render('recipes', { pagetitle: 'Recipes' }); }); module.exports = router;
myapp/routes/tips.js
var express = require('express'); var router = express.Router(); router.get("https://www.computerhope.com/", function(req, res, next) { res.render('tips', { pagetitle: 'Tips For Living Well' }); }); module.exports = router;
Sekundäre Ansichten
Die folgenden Ansichten erben layout.pug.
myapp/views/about.pug
extends layout block mainbody #mainbody section#mainbodyitems p Alice & Bob have been operating their farm stand since 1992.
myapp/views/advice.pug
extends layout block mainbody #mainbody section#mainbodyitems h3 Homesteading Advice p Never, ever stand behind a heifer.
myapp/views/contact.pug
extends layout block mainbody #mainbody section#mainbodyitems h3 Alice & Bob p 1344 Chattanooga Way p Homestead, VT 05401 p (802) 555-5555
myapp/views/recipes.pug
extends layout block mainbody #mainbody section#mainbodyitems h3 Alice's Recipes p b No-knead next-day dutch oven bread p.ingredient 1/4 tsp active dry yeast p.ingredient 3 cups all-purpose flour p.ingredient 1 1/2 tsp salt p.ingredient Cornmeal or wheat bran for dusting p In a large bowl, dissolve yeast in water. p Add the flour and salt, stirring until blended. p Cover bowl. Let rest at least 8 hours, preferably 12 to 18, at warm room temperature, about 70 degrees. p When the surface of the dough is dotted with bubbles, it's ready to be folded. Lightly flour a work surface. Sprinkle flour on the dough and fold it over on itself once or twice. Cover loosely and let it rest about 15 minutes. p Using just enough flour to keep the dough from sticking, gently shape it into a ball. Generously coat a clean dish towel with flour, wheat bran, or cornmeal. Put the seam side of the dough on the towel. Cover with another towel and let rise for 1 to 2 hours. p Heat oven to 475°. Cover and bake for 30 minutes.
myapp/views/tips.pug
extends layout block mainbody #mainbody section#mainbodyitems h3 Alice's Tips p Always rise before the sun. p Never use fake maple syrup. p If the bear is black, be loud, attack. p If the bear is brown, play dead, lie down.
Aussehen
Im Hochformat wird über das Menü auf sekundäre Routen zugegriffen.
Im Querformat sind sie über die Kopfzeile und das linke Bedienfeld zugänglich.