koa-2

MVC 分層

代碼地址: https://github.com/ZQ-jhon/koa-starter
MVC 是個老生常談的概念了。
M = Model, V = View , C = Controller , angularjs 就是典型的 MVC 框架。
Angular (指Angular 2+, 下同) 中,C 被拆分成 ViewModel ,因此稱之爲 MVVM 框架:
M = model 數據,驅動渲染的能源
V = View 視圖層,指代用戶可以看到的前端界面
ViewModel = 處理數據和視圖之間的關係

那麼,在 KOA 中, MVC 指代的又是什麼呢?

C,Controller 層

先不急着回答,把上一次的代碼捋一捋,進一步優化一下。
由於之前所有的對於請求參數和數據的處理都放在 APP.js ,隨着需求的增加,導致難以維護,先讓我們給代碼分層:

/** app.js 中新增 `router.js`,專門用來處理路由相關的東西 
*   router.js
*  
*/
const router = require('koa-router')();
module.exports = (app) => {
   app.use(async (ctx, next) => {
       ctx.body = `
         <form action="/submit" method="post">
           <input name="account" type="text"> 賬號
           <br/>
           <input name="password" type="password"> 密碼
           <br/>
           <button>提交</button>
         </form>
       `;
       await next();
   });
   app.use(async (ctx, next) => {
       if (ctx.request.url === '/submit') {
           ctx.response.type = 'application/json';
           ctx.response.body = ctx.request.body;
       }
       await next();
   });

   // add router middleware:
   app.use(router.routes())
}
}

整個 router 也被編寫並導出爲一個函數,接受 koa 的實例 app,來進行中間件的使用。

還不夠完美,router 中仍然存在大量的與路由無關的代碼,我們進一步分層:

/**
* 新建 index.controller.js
* index.controller.js 的職責就是:一旦收到命令,就渲染並返回表單頁面
*/

module.exports =  async (ctx, next) => {
  ctx.response.type = 'text/html';
  ctx.body = `
      <form action="/submit" method="post">
        <input name="account" type="text"> 賬號
        <br/>
        <input name="password" type="password"> 密碼
        <br/>
        <button>提交</button>
      </form>
    `;
  await next();
}

/**
* 同理,新建 post.controller.js
* post.controller.js 的職責是:收到命令,就解析 body 中傳來的數據,並渲染返回給前端
*/

module.exports = async (ctx, next) => {
    ctx.response.type = 'application/json';
    ctx.response.body = ctx.request.body;
}

現在的文件結構應該如下:

|--node_modules
|--package.json
|--app.js
|--index.controller.js
|--post.controller.js
|--router.controller.js

(如果讀者嫌亂,可以增加 controllers 文件夾 和 routers 文件夾,將對應後綴的文件丟到對應的目錄,並更新文件的引用路徑。)

我們現在更新目錄:

|--node_modules
|--package.json
|--app.js
|--contollers
    |--index.controller.js
    |--post.controller.js
|--routers
    |--routers.controller.js

VSCODE 提示更新引用,NICE。
在這裏插入圖片描述

通過上面的代碼可以看到,兩個新建的 controller 文件,都是在處理自己的業務職責,即渲染並返回對應的數據,他們不關心路由是不是命中了自己,做到了職責單一。

我們現在在 CMD 中輸入 node app.js 發現程序還是按照預期來執行,這裏就不貼圖了。

現在,按照 MVC 框架的思想來理解,業務處理的部分就是 C => controller ,我們已經完成了。

下面來看 View 層是啥?
假設我們現在有 100 個不同的路由來處理請求,並且每個路由要返回不同的頁面,我們肯定不希望手寫 100 個 html ,代碼量太大了。
爲了解放生產力,我們不得不使用模板引擎,例如 ejs , jade,nunjucks 等等,由於 nunjucks 是 mozilla 開發的,就用它吧!(官方文檔支持中文:官方文檔

// 安裝 及 使用
// 隨便在哪新建一個 js 文件
const nunjucks = require('nunjucks');
const result = nunjucks.renderString(`hello, {{name}}`, {name: 123});
console.log(result);

// 通過 node.js 執行
在這裏插入圖片描述

如果你寫過 Angular,Nunjucks 的東西簡直是跟 Angular 的模板語法一毛一樣
支持管道,{{}} ,邏輯判斷,循環,繼承,還有:
防止 XSS 攻擊,支持可配置的轉義 消毒(sanitizer)

const nunjucks = require('nunjucks');
nunjucks.configure('./', {autoescape: true});
// 默認對當前文件夾下的文件進行轉義過濾,消毒處理

髒活都被 nunjucks 幹完了。

使用 nunjucks

下面,我們將 默認 路由下,返回 post 頁面的代碼,用 nunjucks 來進行重構

在 controller 層同級下,新建 views 目錄,然後
新建 from.html 模板文件

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>form</title>
</head>
<body>
<!--注意,這裏使用了 name 變量,看看待會怎麼使用它! -->
    <h1>{{ name }}</h1>
    <form action="/submit" method="post">
        <input name="account" type="text"> 賬號
        <br/>
        <input name="password" type="password"> 密碼
        <br/>
        <button>提交</button>
      </form>
</body>
</html>

接着在 renderers 下新建 renderForm.js

const nunjucks = require('nunjucks');
nunjucks.configure('views', { autoescape: true });
const htmlRenderFn = (object) => nunjucks.render(`form.html`, object);
module.exports = htmlRenderFn;

接着,修改原本在 index.controller.js 中渲染的函數

const renderForm = require('../views/renderForm');
module.exports =  async (ctx, next) => {
  ctx.response.type = 'text/html';
  ctx.body = renderForm({name: 'Hello, nunjucks'});
  await next();
}

回到第二個標題拋出的問題,我的理解是,KOA 中的 MVC :
M = 泛指整個通信過程中所有的數據,包括但不限於 http 請求中傳遞的數據或者路由參數、query 參數、post body 體,甚至 view 層 中 nunjucks 渲染的數據來源。
V = view,返回給前端的視圖
C = controller 控制器

未完待續…

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章