Como criar um site usando Node.js e Express
Este exemplo cria um site usando Node.js para fornecer um comportamento lógico do site. Usando a estrutura Express.js, o site é implementado como um aplicativo da web, com roteamento lógico para outras seções do site.
O HTML e CSS são baseados no design de nosso site responsivo usando CSS Grid e Flexbox. O HTML é refatorado como um modelo, portanto, o código de layout pode ser reutilizado ao adicionar novas páginas.
Nó de instalação
Node.js, também chamado de Node, é um ambiente de tempo de execução para escrever aplicativos do lado do servidor em JavaScript.
Se o Node já estiver instalado em seu computador, você pode pular esta seção e prosseguir para fazer um novo aplicativo Express.
Baixe o instalador do Node do site oficial de downloads do Node.js. Escolha a versão LTS (suporte de longo prazo) para o seu sistema operacional.
Windows e macOS
Abra e execute o instalador do Node (.msi no Windows, .pkg no macOS).
No Windows, na tela de instalação denominada Ferramentas para Módulos Nativos, marque a caixa Instalar automaticamente as ferramentas necessárias.
Linux
Em sistemas Linux, você pode instalar o Node usando seu gerenciador de pacotes, instalar os binários compilados manualmente ou construir o Node a partir da fonte. Para obter informações detalhadas, consulte o wiki oficial de instalação do Node.js.
Todos os sistemas operacionais
Quando a instalação for concluída, abra um terminal ou janela de prompt de comando. Execute o seguinte comando para atualizar o npm, o gerenciador de pacotes do Node. A opção -g (global) especifica que o software é instalado em todo o sistema, não apenas no aplicativo Node atual.
janelas
npm install -g npm
Linux e macOS
sudo npm install -g npm
Por fim, use o npm para instalar globalmente o aplicativo express-generator.
janelas
npm install -g express-generator
Linux e macOS
sudo npm install -g express-generator
Faça um novo aplicativo Express
Em um terminal ou janela de prompt de comando, gere um novo aplicativo Express.js. Em nosso exemplo, o nome do aplicativo é myapp e o mecanismo de visualização é especificado como pug.
express myapp --view="pug"
Mude o diretório para o novo aplicativo Express.
cd myapp
No diretório do aplicativo Express, use npm install para baixar e instalar as dependências necessárias, conforme listado no arquivo package.json.
npm install
Se alguma atualização de segurança estiver disponível para as dependências instaladas, uma notificação será exibida.
found 1 low severity vulnerability run `npm audit fix` to fix them, or `npm audit` for details
Em caso afirmativo, aplique as atualizações de segurança.
npm audit fix
Instale o nodemon
No diretório do aplicativo Express, instale o nodemon. A opção –save-dev indica que o nodemon é uma dependência de desenvolvimento. Não é usado no próprio aplicativo, mas é uma ferramenta usada durante o desenvolvimento.
npm install --save-dev nodemon
Adicionar um script de inicialização de desenvolvimento
Um script de inicialização de desenvolvimento fornece uma maneira de iniciar seu aplicativo da web com opções que ajudam a desenvolver o aplicativo, como mensagens de erro detalhadas.
Em um editor de texto, abra o arquivo package.json no diretório do aplicativo. Este arquivo JSON especifica as dependências usadas pelo seu aplicativo Node. Além disso, ele contém scripts de inicialização nomeados que iniciam o aplicativo de maneiras diferentes.
Em package.json, localize a entrada “scripts”. Por padrão, ele contém apenas um script (“iniciar”).
"scripts": { "start": "node ./bin/www" },
Adicione uma nova linha que defina um script devstart como segue.
Linux e macOS
"scripts": { "start": "node ./bin/www", "devstart": "DEBUG=myapp:* nodemon ./bin/www" },
janelas
"scripts": { "start": "node ./bin/www", "devstart": "SET DEBUG=myapp:* & nodemon ./bin/www" },
Esses scripts (“start” e “devstart”) podem ser executados executando o comando npm run scriptname.
O comando npm run devstart inicia o aplicativo com dois recursos de desenvolvimento adicionais habilitados.
- A variável de ambiente DEBUG é definida, especificando que o log do console e as páginas de erro, como HTTP 404, exibem informações adicionais, como um rastreamento de pilha.
- Além disso, o nodemon monitora certos arquivos importantes do site. Se você modificar esses arquivos, como redesenhar uma página ou modificar o conteúdo estático, o nodemon reinicia automaticamente o servidor para refletir as mudanças.
Inicie o servidor da web no modo de desenvolvimento.
npm run devstart
Se o Firewall do Windows bloquear o aplicativo do servidor web, clique em Permitir acesso.
Visualize o aplicativo da web
Quando o aplicativo está em execução, seu computador atua como um servidor web, servindo HTTP na porta 3000.
Para visualizar o site, abra um navegador da web no endereço localhost: 3000.
Qualquer dispositivo conectado à sua rede local pode visualizar o aplicativo no endereço ipaddress: 3000, onde ipaddress é o endereço IP local do computador que executa o aplicativo.
Se você não tiver certeza de qual é o endereço IP local do computador, consulte: Como encontrar meu endereço IP.
Para visualizar o site em um dispositivo móvel, conecte seu Wi-Fi à rede local e abra o endereço em um navegador.
Modelos HTML
Nosso exemplo usa CSS, JavaScript e HTML de como criar um site responsivo usando CSS Grid e Flexbox. O CSS e o JavaScript são usados literalmente. O HTML é refatorado para uma linguagem de modelos.
Usando uma linguagem de modelos, o código de layout é escrito apenas uma vez e herdado por outras páginas.
O software que converte um modelo em seu formato final é chamado de processador de modelo. No contexto do HTML, um processador de template é chamado de view engine.
Express.js oferece suporte a vários mecanismos de visualização, incluindo Pug.
Visão geral do Pug
A linguagem Pug descreve documentos HTML de uma forma que fornece benefícios e recursos adicionais. Os arquivos Pug são renderizados em HTML quando o usuário os solicita.
A sintaxe da linguagem do Pug elimina a necessidade de as tags serem fechadas ou entre colchetes. Ele também oferece suporte a modelos herdados, iteração, condicionais e avaliação de JavaScript.
Exemplo de conversão de HTML para Pug
Estas são as primeiras linhas do HTML de como criar um site responsivo usando CSS Grid e 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>
No Pug, o mesmo HTML pode ser escrito assim.
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')") ☰
As tags de elemento são escritas sem colchetes. Os elementos filhos são recuados. O nível de recuo determina o escopo de um elemento, portanto, as tags de fechamento não são necessárias.
Os seletores CSS “id” e “class” podem ser escritos como element # id, element.class, element # id.class, etc. Se nenhum elemento for especificado, o elemento será considerado um div. Por exemplo,
Após o nome do elemento e seus seletores, os atributos podem ser especificados entre parênteses, como uma lista delimitada por vírgulas. Por exemplo:
HTML
<div class="button" onmouseover="glow()" onclick="start()">
Pug
.button(onmouseover="glow()", onclick="start()")
Listando vários elementos em uma linha
Se o elemento for seguido por dois-pontos (:), ele pode ser seguido por um elemento filho na mesma linha. As duas seções a seguir do Pug produzem a mesma saída HTML.
a(href="/home") p Home
a(href="https://www.computerhope.com/home"): p Home
Ambos os itens acima são processados no seguinte HTML.
<a href="https://www.computerhope.com/home"><p>Home</p></a>
Avaliando JavaScript
Se o elemento for seguido por um sinal de igual (=), tudo o que segue nessa linha é interpretado como código em buffer. O código é avaliado como JavaScript e a saída é “armazenada em buffer” (incluída como o conteúdo do elemento). Em sua forma mais simples, o código em buffer pode ser o nome de uma variável, passada pelo aplicativo.
Por exemplo, o roteador de aplicativo da página inicial, index.js, passa a variável title com o valor “Our Farm Stand” para o método express.Router (), que o passa para Pug. Quando Pug renderiza layout.pug, a seguinte linha:
title= pagetitle
… é interpretado como:
title Our Farm Stand
… que é processado como o seguinte HTML:
<title>Our Farm Stand</title>
Herança de modelo
Os documentos Pug podem herdar outros documentos Pug usando as palavras-chave extends e block.
Por exemplo, você pode criar um layout básico de site, layout.pug, com elementos compartilhados da página.
doctype html html head title Page Title body p Content block foo
A instrução block foo diz “insira um bloco de conteúdo aqui, denominado foo, especificado em outro documento Pug que herda este modelo.”
Os documentos que herdam layout.pug devem começar com a instrução extends layout e conter uma instrução block foo no nível de recuo superior (no início de uma nova linha). Os filhos desta instrução “block foo” são inseridos no modelo na localização do bloco correspondente.
Um documento Pug pode herdar layout.pug como o seguinte.
extends layout block foo p This is the home page.
Quando o documento é renderizado, o mecanismo Pug carrega o arquivo layout.pug. O bloco de linha foo em layout.pug é substituído por p Esta é a página inicial.
Visão geral do aplicativo Express padrão
A estrutura padrão do aplicativo Express está listada aqui, com descrições de cada arquivo e diretório.
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.
A funcionalidade principal do site é definida em app.js. As rotas são nomeadas e especificadas neste arquivo.
Uma rota é uma página ou seção do site com um caminho exclusivo no URL, como www.example.com/search, www.example.com/login, etc. Essas rotas são nomeadas e associadas a scripts de lógica de rota, em app.js.
Os scripts de lógica de rota são armazenados na pasta de rotas. Quando um usuário solicita uma rota, seu script de lógica de rota processa os dados da solicitação HTTP e envia uma resposta.
A pasta de visualizações contém os modelos HTML, chamados de visualizações, que são processados pelo mecanismo de visualização (Pug).
Implementação: JavaScript, CSS e Pug
O código a seguir implementa o aplicativo da web Express.
Estrutura de arquivo do aplicativo
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
A lógica do aplicativo principal é essencialmente a mesma do aplicativo Express padrão, com rotas adicionais definidas. A rota de “usuários” é removida.
/\/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;
myapp \/routes \/layout.pug
O arquivo layout.pug contém o layout principal da página, que é compartilhado por todas as páginas do site. Ele contém tudo o que é necessário para exibir uma página, exceto o conteúdo mainbody (bloco mainbody).
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
O arquivo index.pug estende layout.pug e contém conteúdo principal para a rota /.
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
myapp \/routes \/index.js
O arquivo index.js contém lógica para a rota /.
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
O arquivo menu.js contém o JavaScript do exemplo Grid e Flexbox. Ele implementa a função de alternância do menu.
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
O arquivo style.css contém o CSS do exemplo Grid e 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 */ } }
Rotas secundárias
Os arquivos a seguir contêm a lógica para rotas secundárias – Sobre, Conselho, Contato, etc.
myapp \/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 \/advis.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;
myapp \/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;
Vistas secundárias
As visualizações a seguir herdam 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 \/advis.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.
Aparência
No modo retrato, as rotas secundárias são acessadas no menu.
No modo paisagem, eles são acessíveis no cabeçalho e no painel esquerdo.
0 Comments