כיצד ליצור אתר באמצעות Node.js ו- Express



יישום האינטרנט Node.js

דוגמה זו יוצרת אתר באמצעות Node.js כדי לספק התנהגות לוגית של אתרים. באמצעות Express.js מִסגֶרֶת , האתר מיושם כיישום אינטרנט, עם ניתוב לוגי לחלקים אחרים באתר.



ה- HTML וה- CSS מבוסס על שלנו עיצוב אתרים רספונסיבי באמצעות CSS Grid ו- Flexbox . ה- HTML משובץ כ- תבנית , כך שניתן יהיה לעשות שימוש חוזר בקוד הפריסה בעת הוספת דפים חדשים.

התקן את הצומת

Node.js, נקרא גם צוֹמֶת , היא סביבת זמן ריצה לכתיבת יישומים בצד השרת JavaScript .



הערה

אם הצומת כבר מותקן במחשב שלך, תוכל לדלג על חלק זה ולהמשיך ל צור אפליקציית אקספרס חדשה .

הורד את מתקין הצומת מה- אתר הורדות רשמי של Node.js . בחר בגרסת LTS (תמיכה לטווח ארוך) עבור מערכת ההפעלה שלך.



חלונות ו- macOS

פתח והפעל את מתקין הצומת ( .msi ב- Windows, .pkg ב- macOS).

ב- Windows, במסך ההתקנה שכותרתו כלים למודולים מקוריים , בדוק את הקופסא התקן אוטומטית את הכלים הדרושים .

לינוקס

במערכות לינוקס, אתה יכול להתקין את Node באמצעות מנהל החבילות שלך, להתקין את הבינאריות המהודרות באופן ידני או לבנות את Node מהמקור. לקבלת מידע מפורט, עיין ב הוויקי הרשמי של Node.js .

כל מערכות ההפעלה

בסיום ההתקנה, פתח מסוף או חלון שורת פקודה. הפעל את הפקודה הבאה לעדכון מעל פני הים , מנהל חבילות הצומת. ה מתג (גלובלי) מציין שהתוכנה מותקנת בכל המערכת, לא רק אפליקציית ה- Node הנוכחית.

חלונות

npm install -g npm

לינוקס ו- macOS

sudo npm install -g npm

לבסוף, השתמש ב- npm כדי להתקין את ה- מחולל אקספרס יישום.

חלונות

npm install -g express-generator

לינוקס ו- macOS

sudo npm install -g express-generator

צור אפליקציית אקספרס חדשה

במסוף או בחלון שורת הפקודה, צור יישום Express.js חדש. בדוגמה שלנו, שם האפליקציה הוא מייאפ , ומנוע התצוגה מוגדר כ- סוֹלֵד .

express myapp --view='pug'

שנה ספרייה לאפליקציית האקספרס החדשה.

cd myapp

בספריית האפליקציות אקספרס, השתמש התקנת npm להורדה והתקנה של התלות הנדרשת, כמפורט בקובץ package.json.

npm install

אם קיימים עדכוני אבטחה לתלות המותקנת, מוצגת התראה.

found 1 low severity vulnerability run 'npm audit fix' to fix them, or 'npm audit' for details

אם כן, החל את עדכוני האבטחה.

npm audit fix

התקן נודמון

בספריית האפליקציות אקספרס, התקן נודמון . האפשרות -שמור- dev מציין כי נודמון הוא תלות בהתפתחות. הוא אינו משמש ביישום עצמו, אלא הוא כלי המשמש במהלך הפיתוח.

npm install --save-dev nodemon

הוסף סקריפט הפעלה לפיתוח

ל סקריפט הפעלה לפיתוח מספק דרך להפעיל את יישום האינטרנט שלך עם אפשרויות המסייעות לך בפיתוח האפליקציה, כגון הודעות שגיאה גדולות.

בעורך טקסט, פתח את הקובץ package.json בספריית האפליקציות. קובץ JSON זה מציין את התלות המשמשת את אפליקציית הצומת שלך. בנוסף, הוא מכיל שם סקריפטים להפעלה שמתחילים את היישום בדרכים שונות.

ב- package.json, אתר את הערך 'סקריפטים'. כברירת מחדל, הוא מכיל סקריפט אחד בלבד ('התחל').

 'scripts': { 'start': 'node ./bin/www' },

הוסף שורה חדשה המגדירה סקריפט devstart כדלהלן.

לינוקס ו- macOS

 'scripts': { 'start': 'node ./bin/www',  'devstart': 'DEBUG=myapp:* nodemon ./bin/www'  },

חלונות

 'scripts': { 'start': 'node ./bin/www',  'devstart': 'SET DEBUG=myapp:* & nodemon ./bin/www'  },

ניתן לבצע סקריפטים אלה ('התחל' ו- 'devstart') על ידי הפעלת הפקודה ריצה npm שם סקריפט .

הפקודה מעל פני הים הפעל את devstart מפעיל את האפליקציה עם שתי תכונות פיתוח נוספות מופעלות.

  • ה לנפות משתנה הסביבה מוגדר, ומציין כי יומני המסוף ועמודי השגיאה, כגון HTTP 404, מציגים מידע נוסף, כמו מעקב מחסנית.
  • בנוסף, נודמון עוקב אחר קבצי אתרים חשובים מסוימים. אם אתה משנה קבצים אלה, כגון עיצוב מחדש של דף או שינוי תוכן סטטי, nodemon מפעיל מחדש את השרת באופן אוטומטי כדי לשקף את השינויים.

הפעל את שרת האינטרנט במצב פיתוח.

npm run devstart
עֵצָה

אם חומת האש של Windows חוסמת את יישום שרת האינטרנט, לחץ על אפשר גישה .

תצוגה מקדימה של אפליקציית האינטרנט

כאשר היישום פועל, המחשב שלך פועל כשרת אינטרנט ומגיש HTTP ב נמל 3000 .

לתצוגה מקדימה של האתר, פתח דפדפן אינטרנט לכתובת מקום אירוח מקומי: 3000 .

אפליקציית Express.js המוגדרת כברירת מחדל

כל מכשיר המחובר לרשת המקומית שלך יכול להציג את היישום בכתובת כתובת ה - IP : 3000 , איפה כתובת ה - IP הוא המקומי כתובת ה - IP של המחשב שמריץ את האפליקציה.

עֵצָה

אם אינך בטוח מהי כתובת ה- IP המקומית של המחשב, ראה: כיצד למצוא את כתובת ה- IP שלי.

לתצוגה מקדימה של האתר במכשיר נייד, חבר את ה- Wi-Fi שלו לרשת המקומית שלך ופתח את הכתובת בדפדפן.

Express.js בנייד

תבניות HTML

הדוגמה שלנו משתמשת ב CSS, JavaScript ו- HTML מאופן יצירת אתר רספונסיבי באמצעות CSS Grid ו- Flexbox. משתמשים במילה CSS וב- JavaScript. ה- HTML משובץ מחדש ל- a שפת תבניות .

באמצעות שפת תבנית, קוד הפריסה נכתב פעם אחת בלבד, ומועבר לדפים אחרים.

התוכנה הממירה תבנית לפורמט הסופי שלה נקראת a מעבד תבניות . בהקשר של HTML, מעבד תבניות נקרא a להציג מנוע .

Express.js תומך במספר מנועי תצוגה, כולל סוֹלֵד .

סקירה כללית של פאג

שפת פאג מתאר מסמכי HTML, באופן המספק יתרונות ותכונות נוספות. קבצי פאג מועברים ל- HTML כאשר המשתמש מבקש אותם.

תחביר השפה של פאג מסיר את הצורך תגים להיסגר, או להיסגר בסוגריים. הוא תומך גם בתבניות בירושה, איטרציה, תנאים , והערכת JavaScript.

דוגמה להמרה של HTML ל- Pug

אלה השורות הראשונות של HTML מאופן יצירת אתר רספונסיבי באמצעות CSS Grid ו- Flexbox.

 Title 

ב- Pug ניתן לכתוב את אותו HTML כך.

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(hide')') ☰ 

תגי אלמנטים נכתבים ללא סוגריים. אלמנטים של ילד מוכנסים. רמת הכניסה קובעת את היקף האלמנט, ולכן אין צורך בתגיות סגירה.

ניתן לכתוב את בוחרי ה- CSS 'id' ו- 'class' כ- אלמנט # id , element.class , אלמנט # id.class וכו 'אם לא צויין שום אלמנט, ההנחה היא כי האלמנט הוא div. לדוגמה, ב- HTML ניתן לכתוב בשם .foo בפאג.

לאחר שם האלמנט ובוחריו, ניתן לציין תכונות בסוגריים, כרשימה המופרדת בפסיקים. לדוגמה:

HTML

 

סוֹלֵד

.button(onmouseover='glow()', )

רישום מספר אלמנטים בשורה אחת

אם האלמנט ואחריו נקודתיים ( : ), יכול להיות אחריו אלמנט ילד באותה שורה. שני החלקים הבאים של פאג מייצרים את אותה פלט HTML.

a(href='tmp/home') p Home
a(href='tmp/home'): p Home 

שני האמור לעיל מועברים ל- HTML הבא.

 

Home

הערכת JavaScript

אם אחרי האלמנט מופיע סימן שווה ( = ), כל מה שאחריו באותה שורה מתפרש כ קוד שנאגר . הקוד מוערך כ- JavaScript, והפלט הוא 'מאגר' (כלול כתוכן האלמנט). בצורתו הפשוטה ביותר, קוד שנאגר יכול להיות שם של משתנה, המועבר על ידי היישום.

לדוגמה, נתב האפליקציה עבור דף הבית, index.js , מעביר את המשתנה כותרת עם הערך 'דוכן החווה שלנו' לשיטה express.Router () , שמעביר אותו לפאג. כשפאג מעבד layout.pug , השורה הבאה:

title= pagetitle

... מתפרש כ:

title Our Farm Stand

... שמוצג כ- HTML הבא:

Our Farm Stand

ירושת תבנית

מסמכי פאג יכולים לרשת מסמכי פאג אחרים באמצעות מילות המפתח מרחיב ו לַחסוֹם .

לדוגמה, תוכל ליצור פריסת אתרים בסיסית, layout.pug , עם אלמנטים משותפים של הדף.

doctype html html head title Page Title body p Content  block foo  

ה לחסום foo ההצהרה אומרת 'הכנס כאן גוש תוכן בשם foo , שצוין במסמך Pug אחר שיורש תבנית זו. '

מסמכים שעוברים בירושה layout.pug חייבים להתחיל בהצהרה מרחיב פריסה , ומכילים א לחסום foo הצהרה ברמת הכניסה העליונה (בתחילת שורה חדשה). הילדים של הצהרת 'חסום foo' מוכנסים לתבנית במיקום הבלוק המתאים.

מסמך פאג יכול לרשת layout.pug כמו הבא.

extends layout block foo p This is the home page.

כאשר המסמך מועבר, מנוע הפאג טוען את הקובץ layout.pug. השורה לחסום foo ב- layout.pug מוחלף ב- זה דף הבית .

סקירה כללית של אפליקציית Express המהווה ברירת מחדל

מבנה ברירת המחדל של אפליקציית אקספרס מופיע כאן, עם תיאורים של כל קובץ וספרייה.

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. 

פונקציונליות הליבה של האתר מוגדרת ב app.js . מסלולים נקובים ומצוינים בקובץ זה.

ל מַסלוּל הוא דף או קטע של האתר עם נתיב ייחודי בכתובת האתר, כגון www.example.com /לחפש , www.example.com /התחברות וכו 'מסלולים אלה נקראים, ומשויכים לתסריטים לוגיים של מסלולים, ב- app.js .

סקריפטים לוגיים של מסלול מאוחסנים ב- מסלולים תיקיה. כאשר משתמש מבקש מסלול, סקריפט לוגיקת המסלול שלו מעבד את נתוני בקשת ה- HTTP ושולח תגובה.

ה נופים התיקיה מכילה את תבניות ה- HTML, הנקראות נופים , אשר מעובדים על ידי מנוע התצוגה (Pug).

יישום: JavaScript, CSS ו- Pug

הקוד הבא מיישם את אפליקציית האינטרנט Express.

מבנה קובץ אפליקציה

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 

myapp / app.js

ההיגיון המרכזי באפליקציות זהה למעשה לאפליקציית האקספרס המוגדרת כברירת מחדל, עם הגדרת מסלולים נוספים. מסלול 'המשתמשים' הוסר.

// 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('/', 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;

myapp / routes / layout.pug

ה layout.pug הקובץ מכיל את פריסת הליבה של הדף, המשותפת לכל עמוד באתר. הוא מכיל את כל הדרוש להצגת דף, למעט תוכן הראשי של הגוף ( חסום גוף מרכזי ).

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='tmp/stylesheets/style.css') body #menu section#menuitems .menubutton h1.menubutton(hide')') ☰ a(href='tmp/') h3.menuhead Our Farm Stand a(href='tmp/tips') h3.sectrule Tips for living well a(href='tmp/recipes') h3 Recipes a(href='tmp/advice') h3 Homesteading advice a(href='tmp/about') h3.sectrule About Us a(href='tmp/contact') h3 Contact Us #container #header a(href='tmp/') h1.logo Our Farm Stand .headspace h1.menubutton(show')') ☰ h1.placeholder ☰ h2.navitem a(href='tmp/about') .clickable-area About Us h2.navitem a(href='tmp/contact') .clickable-area Contact Us #panel.left section#sections .sectionlink a(href='tmp/tips') .clickable-area Tips for living well .sectionlink a(href='tmp/recipes') .clickable-area Recipes .sectionlink a(href='tmp/advice') .clickable-area Homesteading advice  block mainbody  #panel.right h3 Our friends section#partners.tall .partnerlink a(href='tmp/') .clickable-area Green Valley Greens .partnerlink a(href='tmp/') .clickable-area Turkey Hill Farm .partnerlink a(href='tmp/') .clickable-area Burt's Maple Syrup .partnerlink a(href='tmp/') .clickable-area Only Organic Seeds #footer p Copyright  2020 Alice & Bob's Farm Stand 

myapp / views / index.pug

ה index.pug הקובץ מרחיב את layout.pug, ומכיל תוכן mainbody למסלול / .

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='tmp/') .clickable-area Burt's Maple Syrup .partnerlink.wide a(href='') .clickable-area Only Organic Seeds .bodyspace

myapp / routes / index.js

הקובץ index.js מכיל היגיון למסלול / .

var express = require('express'); var router = express.Router(); router.get('/', function(req, res, next) { res.render('index', { pagetitle: 'Our Farm Stand' }); }); module.exports = router;

הקובץ menu.js מכיל את ה- JavaScript מהדוגמה Grid ו- Flexbox. זה מיישם את פונקציית החלפת התפריט.

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; } }

myapp / public / stylesheets / style.css

הקובץ style.css מכיל את ה- CSS מהדוגמה של רשת ו- Flexbox.

/* 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 */ } }

מסלולים משניים

הקבצים הבאים מכילים את ההיגיון במסלולים משניים - אודות, ייעוץ, קשר , וכו.

myapp / routes / about.js

var express = require('express'); var router = express.Router(); router.get('/', 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('/', function(req, res, next) { res.render('advice', { pagetitle: 'Homesteading Advice' }); }); module.exports = router;

myapp / routes / contact.js

var express = require('express'); var router = express.Router(); router.get('/', 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('/', 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('/', function(req, res, next) { res.render('tips', { pagetitle: 'Tips For Living Well' }); }); module.exports = router;

השקפות משניות

התצוגות הבאות יורשות את 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.

מראה חיצוני

במצב פורטרט, ניתן לגשת למסלולים משניים בתפריט.

נוף פורטייט

במצב נוף, הם נגישים מהכותרת ומהחלונית השמאלית.

נוף נוף