koa框架会用也会写—(koa-view、koa-static)

栏目: Node.js · 发布时间: 6年前

内容简介:在网络请求中,请求往往分成两种类型,一种是静态资源,直接从服务器的文件存储中读取,一种是动态资源,一般需要先从数据库获取数据,然后经过一定的处理,最后返回给客户端。根据上面的思想,所以实现简单版的static,可以将static单独存在一个js文件按中,然后require进来,这样使用和koa一样:以ejs模板为例,假设要渲染的模板是:
  • 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);
复制代码

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

笨办法学Python 3

笨办法学Python 3

[美]泽德 A. 肖 / 王巍巍 / 人民邮电出版社 / 2018-6-1 / CNY 59.00

本书是一本Python入门书,适合对计算机了解不多,没有学过编程,但对编程感兴趣的读者学习使用。这本书以习题的方式引导读者一步一步学习编程,从简单的打印一直讲到完整项目的实现,让初学者从基础的编程技术入手,最终体验到软件开发的基本过程。本书是基于Python 3.6版本编写的。 本书结构非常简单,除“准备工作”之外,还包括52个习题,其中26个覆盖了输入/输出、变量和函数3个主题,另外26个......一起来看看 《笨办法学Python 3》 这本书的介绍吧!

JS 压缩/解压工具
JS 压缩/解压工具

在线压缩/解压 JS 代码

UNIX 时间戳转换
UNIX 时间戳转换

UNIX 时间戳转换

正则表达式在线测试
正则表达式在线测试

正则表达式在线测试