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

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

内容简介:在网络请求中,请求往往分成两种类型,一种是静态资源,直接从服务器的文件存储中读取,一种是动态资源,一般需要先从数据库获取数据,然后经过一定的处理,最后返回给客户端。根据上面的思想,所以实现简单版的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);
复制代码

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

查看所有标签

猜你喜欢:

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

The Cult of the Amateur

The Cult of the Amateur

Andrew Keen / Crown Business / 2007-6-5 / USD 22.95

Amateur hour has arrived, and the audience is running the show In a hard-hitting and provocative polemic, Silicon Valley insider and pundit Andrew Keen exposes the grave consequences of today’s......一起来看看 《The Cult of the Amateur》 这本书的介绍吧!

html转js在线工具
html转js在线工具

html转js在线工具

RGB CMYK 转换工具
RGB CMYK 转换工具

RGB CMYK 互转工具