koa框架會用也會寫—(koa-view、koa-static)
阿新 • • 發佈:2018-12-13
Koa中常用的中介軟體:
- koa-session:讓無狀態的http擁有狀態,基於cookie實現的後臺儲存資訊的session
- koa-mysql:封裝了需要用到的SQL語句
- koa-mysql-session:當不想讓session儲存到記憶體,而想讓session儲存到mysql資料庫中時使用
- koa-router:後臺會接受到各種請求的url,路由會根據不同的url來使用不同的處理邏輯。
- koa-view:請求html頁面時,後臺會用模板引擎渲染資料到模板上,然後返回給後臺
- koa-static:請求img、js、css等檔案時,不需要其他邏輯,只需要讀取檔案
- koa-better-body:post上傳檔案時,解析請求體
koa系列文章:
靜態資源和動態資源
在網路請求中,請求往往分成兩種型別,一種是靜態資源,直接從伺服器的檔案儲存中讀取,一種是動態資源,一般需要先從資料庫獲取資料,然後經過一定的處理,最後返回給客戶端。
- koa-static:用來處理靜態資源的訪問,因為它不涉及其他的處理過程,只是單純的讀取檔案,所以單獨抽離出來。
- koa-view是用來將資料和模板結合渲染html頁面時採用的,渲染模板的邏輯都市一樣的,所以也單獨抽離出來。
koa-static
- 判斷請求的檔案是否存在,如果存在讀取檔案返回
- 如果請求的檔案不存在,則預設檢視當前檔案下是否有index.html,如果存在返回當前檔案下的index.html
根據上面的思想,所以實現簡單版的static,可以將static單獨存在一個js檔案按中,然後require進來,這樣使用和koa一樣:
const Koa = require('koa'); const path = require('path'); const Router = require('koa-router'); const fs = require('fs'); const {promisify} = require('util'); //將函式promise化 const stat = promisify(fs.stat); //用來獲取檔案的資訊 const mime = require('mime'); //mime型別獲取外掛 let app = new Koa(); let router = new Router(); function static(dir) { return async (ctx,next)=>{ let pathname = ctx.path; //獲取請求檔案的絕對路徑 let realPath = path.join(dir,pathname); try{ let statObj = await stat(realPath); if (statObj.isFile()) { //如果是檔案則讀取檔案,並且設定好相應的響應頭 ctx.set('Content-Type', mime.getType(realPath)+";charset=utf-8"); ctx.body = fs.createReadStream(realPath) } else { //如果不是檔案,則判斷是否存在index.html let filename = path.join(realPath, 'index.html') await stat(filename) ctx.set('Content-Type', "text/html;charset=utf-8"); ctx.body = fs.createReadStream(filename); } }catch(e){ await next(); //交給後面的中介軟體處理 } } } app.use(static(path.resolve(__dirname, 'public'))); app.use(router.routes()); app.listen(3000); 複製程式碼
koa-view
koa-view使用
以ejs模板為例,假設要渲染的模板是:
//template.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>Document</title>
</head>
<body>
<%arr.forEach(a=>{%>
<li><%=a%></li>
<%})%>
</body>
</html>
複製程式碼
渲染頁面的邏輯:
const Koa = require('koa');
const path = require('path');
const Router = require('koa-router')
const views = require('koa-views');
let app = new Koa();
let router = new Router();
app.use(views(path.resolve(__dirname), {
//不設定的話,模板檔案要使用.ejs字尾而不是.htmls字尾
map: { html: 'ejs' }
}));
router.get('/',async (ctx,next)=> {
await ctx.render('template.html',{arr:[1,2,3]})
})
app.listen(3000);
複製程式碼
ejs渲染的原理
koa中會設定採用渲染模板的方式,一般會採用ejs模板引擎渲染頁面:
- 匹配<%=xx%>將其變成${xx}
- 匹配<%xxxx%>將xxxx中的內容拼接起來變成一個函式字串
- 然後通過new Function函式字串生成一個函式執行資料就會返回渲染後的字串
//簡化渲染模板便於理解,去掉其他標籤,真實渲染時,這些標籤時存在的
<body>
<%arr.forEach(a=>{%>
<li><%=a%></li>
<%})%>
</body>
複製程式碼
ejs中的render函式,簡化版本:
function render(r, obj) {
let head = `let str=''\r\n`;
//with可以將變數的上下文指向為obj,所以a => obj.a
head += 'with(b){\r\n'
let content = 'str+=`'
//先將匹配<%=xx%>將其變成${xx}
r = r.replace(/<%=([\s\S]*?)%>/g, function () {
return '${' + arguments[1] + '}'
});
//匹配<%xxxx%>將xxxx中的內容拼接起來變成一個函式主要邏輯
content += r.replace(/<%([\s\S]*?)%>/g, function () {
return '`\r\n' + arguments[1] + "\r\n str+=`"
});
let tail = "`\r\n} \r\n return str";
let fnStr = head + content + tail;
let fn = new Function('b', fnStr)
return fn(obj);
}
//fn= function(b){
// let str='';
// with(b){
// str+='<body>';
// b.arr.forEach(a=>{str += '<li>${a}</li>'});
// str += '</body>';
// }
// return str
//}
複製程式碼
koa-view的原理
function views(p,opts) {
return async(ctx,next)=>{
function render(r, obj) {
let head = `let str=''\r\n`;
head += 'with(b){\r\n'
let content = 'str+=`'
r = r.replace(/<%=([\s\S]*?)%>/g, function () {
return '${' + arguments[1] + '}'
});
content += r.replace(/<%([\s\S]*?)%>/g, function () {
return '`\r\n' + arguments[1] + "\r\n str+=`"
});
let tail = "`\r\n} \r\n return str";
let fnStr = head + content + tail;
let fn = new Function('b', fnStr)
return fn(obj);
}
//在ctx上掛在render函式,讀取檔案,然後渲染
ctx.render = async (filename,obj) => {
let realPath = path.join(p,filename);
let { promisify} = require('util');
let fs = require('fs');
let read = promisify(fs.readFile); //promise化
let r = await read(realPath,'utf8');
ctx.body = render(r, obj);
}
return next();
}
}
module.exports = views;
複製程式碼
渲染頁面的邏輯:
const Koa = require('koa');
const path = require('path');
const Router = require('koa-router')
const views = require('koa-views');
let app = new Koa();
let router = new Router();
app.use(views(path.resolve(__dirname), {
map: { html: 'ejs' }
}));
router.get('/',async (ctx,next)=> {
await ctx.render('template.html',{arr:[1,2,3]})
})
app.listen(3000);
複製程式碼
結語
koa-router中介軟體的原理基本就介紹完了,後面一起學習kao的其他中介軟體:
作者:夢想攻城獅 連結:https://juejin.im/post/5baefe335188255c6a0449c8 來源:掘金 著作權歸作者所有。商業轉載請聯絡作者獲得授權,非商業轉載請註明出處。