iT邦幫忙

1

[12 Project 學 Node.js] Project 2: Basic Express Website

Description:

  • using routing
  • jade template
  • nodemailer module

Express Setup

首先,安裝 express globally
npm install -g express

修改package.json,加入dependencies,一一列出要install的package,改完存檔
"*": 代表要最新版本

{
  "name": "2_express_website",
  "version": "1.0.0",
  "description": "Simple website",
  "main": "app.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "author": "gogocatmario",
  "license": "ISC",
  "dependencies": {
      "body-parser": "*",
      "express": "*",
      "jade": "*",
      "nodemailer": "*"
  }
}

執行batch install
npm會把dependencies列出的所有module都install到project目錄
npm install

Express Example

撰寫app.js,並執行server,打開網頁確認是否有畫面,且console有show log

var express = require('express');
var path = require('path');
var bodyParser = require('body-parser');
var nodemailer = require('nodemailer');

var app = express();

//set up middleware
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({extended: false}));

app.listen(3000);
console.log('Server is running on port 3000...')

因為此時尚未有routing,所以網頁打開會show Cannot GET/
不過先驗證網頁開得起來就行了。

接下來,加入routing

var express = require('express');
var path = require('path');
var bodyParser = require('body-parser');
var nodemailer = require('nodemailer');

var app = express();

//set up middleware
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({extended: false}));

//routing
app.get('/', function(req, res){
    res.send("<h1>Hello world from res</h1>");
    console.log("Hello world from console");
});


app.listen(3000);
console.log('Server is running on port 3000....');

確認網頁有出現 Hello World,就可以往下一步了。

Page Routes & Views (using Jade)

Jade Setup (加到app.js)

//views
app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'jade');

修改 routing (res.send 改成 res.render)

//routing
app.get('/', function(req, res){
    res.render('index');
});

create views 資料夾,用來放jade views

建立index.jade
h3 Hello World

相關連結:
Jade example:
https://naltatis.github.io/jade-syntax-docs/
Jade Convertor:
http://html2jade.org/

上面是簡單的jade使用範例
可以建立一個範本,讓每個jade文件reuse,不需要所有jade都包含完整的code

建立layout.jade,用來當作所有views的範本

doctype html
html
 head
  title my jade template
 body
  h1 Hello World

修改index.jade,開始參考layout.jade,只有block content的位置內容不同

extends layout

block content
 h3 Hello World

為layout.jade加入bootstrap css

create public 資料夾,在public中建立stylesheet資料夾用來放css
將download下來的bootstrap.css copy到stylesheet中

目錄會長得像這樣:

express_website
-node_modules
-public
 -stylesheet
  bootstrap.css
-views
  index.jade
  layout.jade
app.js
package.json

修改app.js

//stylesheet
app.use(express.static(path.join(__dirname, 'public')));

使用jumbotron example建立website

http://getbootstrap.com/getting-started/#examples
from: jumbotron + Starter template

開新文件,copy jumbotron html過來,並修改以下幾個地方:
<a class="navbar-brand" href="#">PC Repairs</a>

從Starter template複製ul,並修改:

          <ul class="nav navbar-nav">
            <li><a href="/">Home</a></li>
            <li><a href="/about">About</a></li>
            <li><a href="/contact">Contact</a></li>
          </ul>

head 中加入bootstrap
<link href="stylesheet/bootstrap.css" rel="stylesheet">

移除不需要的內容後,結果如下


<!DOCTYPE html>
<html>
  <head>
    <title>Jumbotron Template for Bootstrap</title>

    <!-- Bootstrap core CSS -->
    <link href="/stylesheet/bootstrap.css" rel="stylesheet">

  </head>

  <body>

    <nav class="navbar navbar-inverse navbar-fixed-top">
      <div class="container">
        <div class="navbar-header">
          <button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#navbar" aria-expanded="false" aria-controls="navbar">
            <span class="sr-only">Toggle navigation</span>
            <span class="icon-bar"></span>
            <span class="icon-bar"></span>
            <span class="icon-bar"></span>
          </button>
          <a class="navbar-brand" href="#">PC Repairs</a>
        </div>
        <div id="navbar" class="collapse navbar-collapse">
          <ul class="nav navbar-nav">
            <li><a href="/">Home</a></li>
            <li><a href="/about">About</a></li>
            <li><a href="/contact">Contact</a></li>
          </ul>
        </div><!--/.navbar-collapse -->
      </div>
    </nav>

    <!-- Main jumbotron for a primary marketing message or call to action -->
    <div class="jumbotron">
      <div class="container">
        <h1>Hello, world!</h1>
        <p>This is a template for a simple marketing or informational website. It includes a large callout called a jumbotron and three supporting pieces of content. Use it as a starting point to create something more unique.</p>
        <p><a class="btn btn-primary btn-lg" href="#" role="button">Learn more »</a></p>
      </div>
    </div>

    <div class="container">
      <!-- Example row of columns -->
      <div class="row">
        <div class="col-md-4">
          <h2>Heading</h2>
          <p>Donec id elit non mi porta gravida at eget metus. Fusce dapibus, tellus ac cursus commodo, tortor mauris condimentum nibh, ut fermentum massa justo sit amet risus. Etiam porta sem malesuada magna mollis euismod. Donec sed odio dui. </p>
          <p><a class="btn btn-default" href="#" role="button">View details »</a></p>
        </div>
        <div class="col-md-4">
          <h2>Heading</h2>
          <p>Donec id elit non mi porta gravida at eget metus. Fusce dapibus, tellus ac cursus commodo, tortor mauris condimentum nibh, ut fermentum massa justo sit amet risus. Etiam porta sem malesuada magna mollis euismod. Donec sed odio dui. </p>
          <p><a class="btn btn-default" href="#" role="button">View details »</a></p>
       </div>
        <div class="col-md-4">
          <h2>Heading</h2>
          <p>Donec sed odio dui. Cras justo odio, dapibus ac facilisis in, egestas eget quam. Vestibulum id ligula porta felis euismod semper. Fusce dapibus, tellus ac cursus commodo, tortor mauris condimentum nibh, ut fermentum massa justo sit amet risus.</p>
          <p><a class="btn btn-default" href="#" role="button">View details »</a></p>
        </div>
      </div>

      <hr>

      <footer>
        <p>© 2016 Company, Inc.</p>
      </footer>
    </div> <!-- /container -->
  </body>
</html>

copy 改好的 html 到 Jade Convertor,copy output jade to layout.jade

doctype html
html
  head
    title Jumbotron Template for Bootstrap
    // Bootstrap core CSS
    link(href='/stylesheet/bootstrap.css', rel='stylesheet')
  body
    nav.navbar.navbar-inverse.navbar-fixed-top
      .container
        .navbar-header
          button.navbar-toggle.collapsed(type='button', data-toggle='collapse', data-target='#navbar', aria-expanded='false', aria-controls='navbar')
            span.sr-only Toggle navigation
            span.icon-bar
            span.icon-bar
            span.icon-bar
          a.navbar-brand(href='#') PC Repairs
        #navbar.collapse.navbar-collapse
          ul.nav.navbar-nav
            li
              a(href='/') Home
            li
              a(href='/about') About
            li
              a(href='/contact') Contact
        // /.navbar-collapse
    // Main jumbotron for a primary marketing message or call to action
    .jumbotron
      .container
        h1 Hello, world!
        p
          | This is a template for a simple marketing or informational website. It includes a large callout called a jumbotron and three supporting pieces of content. Use it as a starting point to create something more unique.
        p
          a.btn.btn-primary.btn-lg(href='#', role='button') Learn more »
    .container
      // Example row of columns
      .row
        .col-md-4
          h2 Heading
          p
            | Donec id elit non mi porta gravida at eget metus. Fusce dapibus, tellus ac cursus commodo, tortor mauris condimentum nibh, ut fermentum massa justo sit amet risus. Etiam porta sem malesuada magna mollis euismod. Donec sed odio dui.
          p
            a.btn.btn-default(href='#', role='button') View details »
        .col-md-4
          h2 Heading
          p
            | Donec id elit non mi porta gravida at eget metus. Fusce dapibus, tellus ac cursus commodo, tortor mauris condimentum nibh, ut fermentum massa justo sit amet risus. Etiam porta sem malesuada magna mollis euismod. Donec sed odio dui.
          p
            a.btn.btn-default(href='#', role='button') View details »
        .col-md-4
          h2 Heading
          p
            | Donec sed odio dui. Cras justo odio, dapibus ac facilisis in, egestas eget quam. Vestibulum id ligula porta felis euismod semper. Fusce dapibus, tellus ac cursus commodo, tortor mauris condimentum nibh, ut fermentum massa justo sit amet risus.
          p
            a.btn.btn-default(href='#', role='button') View details »
      hr
      footer
        p © 2016 Company, Inc.
    // /container

layout.jade中的main jumbotron段落應該只在index頁面出現
因此將 main jumbotron內容copy到 index.jade

要剪下的部份

    // Main jumbotron for a primary marketing message or call to action
    .jumbotron
      .container
        h1 Hello World
        p
          | This is a template for a simple marketing or informational website. It includes a large callout called a jumbotron and three supporting pieces of content. Use it as a starting point to create something more unique.
        p
          a.btn.btn-primary.btn-lg(href='#', role='button') Learn more »
    .container
      // Example row of columns
      .row
        .col-md-4
          h2 Heading
          p
            | Donec id elit non mi porta gravida at eget metus. Fusce dapibus, tellus ac cursus commodo, tortor mauris condimentum nibh, ut fermentum massa justo sit amet risus. Etiam porta sem malesuada magna mollis euismod. Donec sed odio dui.
          p
            a.btn.btn-default(href='#', role='button') View details »
        .col-md-4
          h2 Heading
          p
            | Donec id elit non mi porta gravida at eget metus. Fusce dapibus, tellus ac cursus commodo, tortor mauris condimentum nibh, ut fermentum massa justo sit amet risus. Etiam porta sem malesuada magna mollis euismod. Donec sed odio dui.
          p
            a.btn.btn-default(href='#', role='button') View details »
        .col-md-4
          h2 Heading
          p
            | Donec sed odio dui. Cras justo odio, dapibus ac facilisis in, egestas eget quam. Vestibulum id ligula porta felis euismod semper. Fusce dapibus, tellus ac cursus commodo, tortor mauris condimentum nibh, ut fermentum massa justo sit amet risus.
          p
            a.btn.btn-default(href='#', role='button') View details » 

在layout.jade剪下的位置加入 block content
(記得空格位置要對齊,不然jade轉html時會搞錯)

     ...
     // /.nav-collapse
 block content
 hr
 footer
     ...

置中footer,加入class="text-center"

...
 footer
  p(class="text-center") © 2016 Company, Inc.
// /container

在 index.jade 使用參數代入值

修改routing,加入title參數

//routing
app.get('/', function(req, res){
    res.render('index', {title: 'Welcome'});
});

修改index.jade,把 Hello World 改成代入參數的格式

...
    .jumbotron
      .container
        h1 #{title}
        p
...

如此一來,index page 就設定好了,接下來加入 about page

修改app.js,加入about routing

app.get('/about', function(req, res){
    res.render('about');
});

create about.jade
p 裡面需要在T前面加上pipeline,不然jade convert時會以為是Tab,就只會show "is the ..."

extends layout

block content
 h1 About Us
 p
  |This is the about page

到這裡,index page 和 about page 都設定完成。

Nodemailer Module

接下來要create contact page

修改app.js,加入contact的routing

app.get('/contact', function(req, res){
    res.render('contact');
});

create contact.jade,建立表單

extends layout

block content
 .container
  form(method='post', action='contact/send')
   h1 Contact
   .form-group
    label Name
    input.form-control(type='text',
    name='name', placeholder='Enter Name')
   .form-group
    label Email
    input.form-control(type='email',
    name='email', placeholder='Enter Email')
   .form-group
    label Message
    textarea.form-control(name='message', placeholder='Enter Message')
   button.btn.btn-default(type='Submit') Submit

Contact 畫面長得像這樣
http://ithelp.ithome.com.tw/upload/images/20170218/20104222LEsukNozRO.png

當點選Submit button時,會透過POST送出request
針對POST request,需要撰寫對應的server動作

修改app.js,加入POST request routing
其中的 user / pass / from 需填寫寄件者的gmail 帳戶和密碼
to 的內容則填寫收件者的 gmail 帳戶

app.post('/contact/send', function(req, res){
    //console.log('Test');

    //specify server options
    var transporter = nodemailer.createTransport({
        service: 'Gmail',
        auth: {
            user: 'your gmail',  
            pass: 'your gmail password'
        }
    });

    //setup mail options
    var mailOptions = {
        from: 'Your Name <your gmail>',
        to: 'your gmail',
        subject: 'Website Submission',
        text: 'You have a submission with the following details... Name: ' + req.body.name + 'Email: ' + req.body.email + 'Message: ' + req.body.message,
        html: '<p>You have a submission with the following details...</p><ul><li>Name: '+req.body.name+'</li><li>Email: '+req.body.email+'</li><li>Message: '+req.body.message+'</li></ul>'
    };

    transporter.sendMail(mailOptions, function(error, info){
        if(error){
            console.log(error);
            res.redirect('/');
        } else {
            console.log('Message Sent: ' + info.response);
            res.redirect('/');
        }
    });

});

註:
講者有提示,目前nodemailer應該只support gmail engine
其他家的email或是自己的SMTP,還沒辦法用nodemailer

到gmail暫時開啟低安全程式存取權限(不然gmail不給寄信),測試完之後記得改回來
(google 關鍵字: gmail access for less secure apps)

http://ithelp.ithome.com.tw/upload/images/20170218/20104222jzzBxtIBEM.png
接著啟動server,填寫contact form按submit,就可以到 gmail 去收信了
http://ithelp.ithome.com.tw/upload/images/20170218/20104222BwFYhkWfU4.png

最後修改幾個地方練習一下改jade,結束這回合。

app.js
app.get('/', function(req, res){
    res.render('index', {title: 'Computer Not Working?'});
});

index.jade
...
  .container
      // Example row of columns
      .row
        .col-md-4
          h2 Virus Removal
....
          h2 Hardware Issues
....
          h2 Software Issues
....

圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言