首頁 / 程式人雜誌 / 2015年5月號

簡單留言系統 -- 使用多頁技術

簡介

在 koa 的 github 官方專案上,提供了一個簡單的網誌留言系統 (說是網誌,但比較像留言),這個系統設計得非常簡單,因此是學習 koa 很好的入門材料,以下是該專案的原始碼網址。

安裝執行過程如下:

D:\git\koa-ex>npm install swig
swig@1.4.2 node_modules\swig
├── optimist@0.6.1 (wordwrap@0.0.2, minimist@0.0.10)
└── uglify-js@2.4.19 (uglify-to-browserify@1.0.2, async@0.2.10, yargs@3.5.4,
source-map@0.1.34)

D:\git\koa-ex>cd blog

D:\git\koa-ex\blog>iojs index
listening on port 3000
  <-- GET /post
  --> GET /post 404 23ms -
  <-- GET /
  --> GET / 200 116ms -
  <-- GET /post/new
  --> GET /post/new 200 18ms -
  <-- POST /post
  --> POST /post 302 47ms -
  <-- GET /
  --> GET / 200 10ms -
  <-- GET /post/new
  --> GET /post/new 200 40ms -
  <-- POST /post
  --> POST /post 302 32ms -
  <-- GET /
  --> GET / 200 25ms -
  <-- GET /post/0
  --> GET /post/0 200 8ms -
  <-- GET /post/1
  --> GET /post/1 200 7ms -
  <-- GET /post/new
  --> GET /post/new 200 5ms -

執行結果如下

這個專案除了採用 koa 框架撰寫伺服端之外,還採用了 swig 這個樣板引擎來呈現網頁,首先讓我們來看伺服端的寫法。

伺服端主程式

檔案: index.js

/**
 * Module dependencies.
 */

var render = require('./lib/render');
var logger = require('koa-logger');
var route = require('koa-route');
var parse = require('co-body');
var koa = require('koa');
var app = koa();

// "database"

var posts = [];

// middleware

app.use(logger());

// route middleware

app.use(route.get('/', list));
app.use(route.get('/post/new', add));
app.use(route.get('/post/:id', show));
app.use(route.post('/post', create));

// route definitions

/**
 * Post listing.
 */

function *list() {
  this.body = yield render('list', { posts: posts });
}

/**
 * Show creation form.
 */

function *add() {
  this.body = yield render('new');
}

/**
 * Show post :id.
 */

function *show(id) {
  var post = posts[id];
  if (!post) this.throw(404, 'invalid post id');
  this.body = yield render('show', { post: post });
}

/**
 * Create a post.
 */

function *create() {
  var post = yield parse(this);
  var id = posts.push(post) - 1;
  post.created_at = new Date;
  post.id = id;
  this.redirect('/');
}

// listen

app.listen(3000);
console.log('listening on port 3000');

您可以看到伺服端的 list 功能之處理,大致如下所示。

app.use(route.get('/', list));
...
function *list() {
  this.body = yield render('list', { posts: posts });
}

這代表當您訪問網址為根目錄時,會呼叫樣板引擎去呈現 list.html 這個樣板,並將貼文 posts 傳入到樣板中。

但是、主程式裏並沒有指定使用哪個樣板引擎,指定的工作是在 lib/render.js 這個檔案裏設定的。(https://github.com/koajs/examples/blob/master/blog/lib/render.js)

var views = require('co-views');

// setup views mapping .html
// to the swig template engine

module.exports = views(__dirname + '/../views', {
  map: { html: 'swig' }
});

您可以看到其中設定使用 swig 樣板引擎,還有其樣板的置放目錄為 views 。

接著讓我們看看樣板到底長甚麼樣? 以下是 list.html 的內容。

檔案: list.html

{% extends 'layout.html' %}

{% block title %}Posts{% endblock %}

{% block content %}
  <h1>Posts</h1>
  <p>You have <strong>{{ posts.length }}</strong> posts!</p>
  <p><a href="/post/new">Create a Post</a></p>
  <ul id="posts">
    {% for post in posts %}
      <li>
        <h2>{{ post.title }}</h2>
        <p><a href="/post/{{ post.id }}">Read post</a></p>
      </li>
    {% endfor %}
  </ul>
{% endblock %}

其中第一行又引入了一個 layout.html 的樣板,其內容如下:

<html>
<head>
  <title>{% block title %}Blog{% endblock %}</title>
  <style>
    body {
      padding: 80px;
      font: 16px Helvetica, Arial;
    }
    h1 {
      font-size: 2em;
    }
    h2 {
      font-size: 1.2em;
    }
    #posts {
      margin: 0;
      padding: 0;
    }
    #posts li {
      margin: 40px 0;
      padding: 0;
      padding-bottom: 20px;
      border-bottom: 1px solid #eee;
      list-style: none;
    }
    #posts li:last-child {
      border-bottom: none;
    }
    textarea {
      width: 500px;
      height: 300px;
    }
    input[type=text],
    textarea {
      border: 1px solid #eee;
      border-top-color: #ddd;
      border-left-color: #ddd;
      border-radius: 2px;
      padding: 15px;
      font-size: .8em;
    }
    input[type=text] {
      width: 500px;
    }
  </style>
</head>
<body>
  <section id="content">
    {% block content %}
      <p>Missing content!</p>
    {% endblock %}
  </section>
</body>
</html>

您可以看到 swig 的樣板有類似繼承的架構,可以透過子樣板中的標記將母樣板的內容修改掉,而這也正是使用樣板引擎的好處之一。

結語

如果還有不清楚的地方,請各位讀者直接參考該專案的原始碼,網址如下:


本文部份內容與大部份圖片修改自 維基百科 , 使用時請遵守 姓名標示、相同方式分享 授權。
編輯: 陳鍾誠 email: ccckmit@gmail.com