koa项目:云音乐应用2——处理页面模板

在搭建好项目的基本框架,和确认渲染模板正常工作之后,我们可以开始进行下一步,来配置注册和登录页面的渲染和功能实现。

页面模板

因为是node.js部分的作业,所以项目需要的几个页面老师都直接提供了。这里提到有几个地方可以优化。

网站架构优化

这一部分老师提供的html文件是按页面来区分的,包括了注册register、登录login、修改edit,还有添加文件add几个页面内容,但是这些内容中其实有很多是重复的。

比如网站的头部和底部都是一样的样式,比如引入的库(bootstrapjquery)在每一个文件中都被引入了一部分,这样其实对于项目的维护会造成很多麻烦。所以这里可以先将页面文件夹(views)中的结构调整一下。

  1. views文件夹中添加components文件夹,并添加header.html,footer.html,links.html文件,分别用来存放头部、底部和链接文件;

  2. views文件夹中添加layout文件夹,并添加main.html文件,用来放置页面中的通用部分,比如header,footer,links

    这里有个很好的例子是我搭建hexo博客时使用的NexT主题,里面把每部分的代码都放在单独的文件里,通过在主文件中引入的方法来使用,但是非常方便,我在修改页面布局的时候能够很轻易就找到代码在哪里:

    image-20180817232442511

    image-20180817232459739

  3. main.html文件中引入header.html,footer.html,links.html文件

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    <html>
    <head>
    <meta charset="UTF-8">
    <title>我的音乐</title>
    <!--加载资源包-->
    {{include '../components/links.html'}}
    </head>
    <body>
    <!--引入头部-->
    {{include '../components/header.html'}}
    <!--中间部分留出来,用于引入其他内容-->
    {{block 'content'}}{{/block}}
    <!--引入底部-->
    {{include '../components/footer.html'}}
    </body>
    </html>
  4. 在其他的页面文件(如注册、登录页面)中,继承main.html的布局,并且将自己的内容填入到上面提到的{{block}}部分

    1
    2
    3
    4
    {{extend "./layout/main.html"}}
    {{block 'content'}}
    ...
    {{/block}}

这里我们不细究具体的布局问题,主要实现node.js的功能。

接着我们给router配置上不同的路径应该渲染哪个模板:

1
2
3
4
5
6
router.get("/register", ctx => {
ctx.render("register");
})
.get("/login", ctx => {
ctx.render("login");
})

现在我们可以来试一试在localhost:9000/register来看看能不能把页面内容渲染出来:

image-20180817231719857

这里读出文件内容是没问题的,但并没有任何样式,在控制台可以看到有一堆资源404的报错。

image-20180817231748477

主要原因是所有的样式表以及相关的库都在public这个文件夹下,public文件夹在文件根目录下。这里是老师留的一个小坑,在于怎么处理静态资源共享的问题。解决静态资源共享其实是一件很简单的事情,使用koa-static中间件,两行代码就能搞定,难点在于到底使哪个文件夹共享。这里因为所有的html文件都是给定的,里面的文件引入路径都有public

image-20180817232158388

(考虑不修改引用路径来解决)如果在按照图中路径的情况,就得让整个项目文件夹共享,这样就会导致所有代码公开,不太安全,但是如果不修改路径的情况下,我们就要做一个调整,即将引用路径中的/public部分去除掉。

这里的解决方法是当服务器接收到以/public开头的请求时,将/public删除:

1
2
3
4
5
6
7
app.use(async (ctx, next) => {
if(ctx.request.url.startsWith('/public')) {
ctx.request.url = ctx.request.url.replace("/public", "");
}
await next();
})
app.use(require("koa-static"){'./public'});

_注意点1:_koa的服务器对象有两个参数,一个是ctx即上下文对象,另一个是next,用于让服务器实现链式操作。一般使用中间件的时候都没有用到这个next,并不是因为next没必要用,而是因为中间件内部已经包含了是否需要next的判断。如果我们自己写中间件,还是应该把next()给加上。

现在我们再来看

image-20180817233943262

image-20180817234003117

这样注册、登录页面就没问题了。

_注意点2:_我刚开始写这两行代码的时候,把使用koa-static放在处理request.url前面了,想法是共享了文件夹,再处理请求,但是这样还是没法读到public文件夹,后来调换顺序解决了这个问题。

我在网上查了一下原因,koa-static中间件其实是一个对koa-send中间件的包装。它的实现机制是根据传入的path查找下级文件是否存在,如果存在就创建一个流,如果不存在就抛出错误。如果处理静态文件的语句在前,那么在请求进来的时候,语句就判断了文件夹不存在,于是就报错了。

所以处理静态资源的语句务必直接处理最终我们希望它处理的请求路径。