koa2 view layer construction
Next to the previous one koa2 routing and mvc building in Js full stack development Let's continue to learn about koa2. In the previous article, we split the project into route, controller and service layers according to the mvc architecture, but the view layer and controller layer are mixed together, and there is no split. In this article, we will use templates and static plug-ins to split the view layer, and make a simple summary of the use of Nunjucks template package.
Article catalog
1. Template and static middleware installation
Or npm for installation
npm install koa-nunjucks-2 -save npm install koa-static -save
2. project structure
├── controller/
│ ├── home.js
├── service/
│ ├── home.js
├── views/
│ ├── common/
│ ├── header.html
│ ├── footer.html
│ ├── layout.html
│ ├── layout-home.html
│ ├── home/
│ ├── index.html
│ ├── login.html
│ ├── success.html
├── public/
│ ├── home/
│ ├── main.css
├── app.js
├── router.js
├── package.json
Three app.js Entrance method
app.js In the entry method, the npm packages of koa-nunjucks-2 and koa static are introduced first, and then their storage paths and relevant parameters are specified respectively.
const Koa = require('koa') const path = require('path') const bodyParser = require('koa-bodyparser') const nunjucks = require('koa-nunjucks-2') const staticFiles = require('koa-static') const app = new Koa() const router = require('./router') // Specify the public directory as the static resource directory to store js css images, etc app.use(staticFiles(path.resolve(__dirname, "./public"),{ maxage: 30*24*60*60*1000 })) app.use(nunjucks({ ext: 'html', path: path.join(__dirname, 'views'), // Specify view directory nunjucksConfig:{ trimBlocks: true // Turn on escape prevention Xss } })) app.use(bodyParser()) router(app) app.listen(3000, () => { console.log('server is running at http://localhost:3000') })
4. Use of views layer
First, the public parent class layout template is introduced, and then other public templates inherit the parent class public template. Then the detailed view pages inherit the corresponding public template.
- layout.html Layout template
<!DOCTYPE html> <html> <head> <title>{{title}}</title> <meta name="viewport" content="width=device-width, initial-scale=1"> {% block head %} {% endblock %} </head> <body> {% include "./header.html" %} {% block body %} {% endblock %} {% include "./footer.html" %} {% block content %} {% endblock %} </body> </html>
- layout-home.html
{% extends "./layout.html" %} {% block head %} <link rel="stylesheet" href="/home/main.css"> {% endblock %} {% block body %} {% block homeBanner %} {% endblock %} <div class="show_time"> <div class="feature-con"> <ul class="feature fn-clear"> <li class="feature-item"><i class="ico"></i> <h4 class="tit">Free resources</h4> </li> <li class="feature-item"><i class="ico"></i> <h4 class="tit">about</h4> </li> </ul> </div> </div> {% endblock %}
- index.html
{% extends "common/layout-home.html" %} {% block homeBanner %} <div class="banner_box"> <div class="banner_inner"> <h2 class="slogan">Gathering talents in the world</h2> <a href="/login" title="gogogo" class="btn" id="gogogo">Sign in</a> </div> </div> {% endblock %} {% block content %} <div class="hp-dialog"> <div class="hp-box"> <form action="/user/register" method="post"> <h1>Login page</h1> <p class="error">{{content}}</p> <input type="text" name="name" placeholder="Please enter the user name: dahlin"> <input type="password" name="password" placeholder="Please enter the password: 123456"> <button>{{btnName}}</button> </form> </div> </div> ,, {% endblock %}
The basic order is index.html Inherit from layout-home.html ,layout-home.html Inherited from layout.html .
5. Use of controller layer
Call the corresponding views layer template in the controller
const HomeService = require('../service/home') module.exports = { index: async(ctx, next) => { await ctx.render("home/index", {title: "xxxx Welcome"}) }, login: async(ctx, next) => { await ctx.render('home/login',{ btnName: 'Submit' }) }, register: async(ctx, next) => { let params = ctx.request.body let name = params.name let password = params.password let res = await HomeService.register(name,password) if(res.status == "-1"){ await ctx.render("home/login", res.data) }else{ ctx.state.title = "Personal Center" await ctx.render("home/success", res.data) } } }
6. Routing router.js
All URLs are initiated from the route. The specific route matches the corresponding url. The url calls the corresponding method in the controller.
const router = require('koa-router')() const HomeController = require('./controller/home') module.exports = (app) => { router.get( '/', HomeController.index ) router.get('/user', HomeController.login) router.post('/user/register', HomeController.register) app.use(router.routes()) .use(router.allowedMethods()) }
The model data model layer is not involved in this chapter, which will be summarized together with the database part in the next chapter.
7. Nunjucks grammar basis
7.1 basic grammar
First, we need to understand several features of nunjuks
variable
{{ username }} {{ foo.bar }} {{ foo["bar"] }}
If the value of the variable is undefined or null, it will not be displayed.
filter
{{ foo | title }} {{ foo | join(",") }} {{ foo | replace("foo", "bar") | capitalize }}
if judgment
{% if variable %} It is true {% endif %} {% if hungry %} I am hungry {% elif tired %} I am tired {% else %} I am good! {% endif %}
for loop
var items = [{ title: "foo", id: 1 }, { title: "bar", id: 2}]
<h1>Posts</h1> <ul> {% for item in items %} <li>{{ item.title }}</li> {% else %} <li>This would display if the 'item' collection were empty</li> {% endfor %} </ul>
Macro macro
Macros: define reusable content, similar to functions in programming languages
{% macro field(name, value='', type='text') %} <div class="field"> <input type="{{ type }}" name="{{ name }}" value="{{ value | escape }}" /> </div> {% endmacro %}
Next, you can use field as a function:
{{ field('user') }} {{ field('pass', type='password') }}
For more grammar information, please refer to Official documents
7.1 inherited functions
The common structure of web pages is mostly the head, intermediate and tail. For multiple pages under the same website, the content of the head and tail are basically the same. So we can use inheritance function to write.
Define one first layout.html
<html> <head> {% block head %} <link rel="stylesheet"> {% endblock %} </head> <body> {% block header %} <h1>this is header</h1> {% endblock %} {% block body %} <h1>this is body</h1> {% endblock %} {% block footer %} <h1>this is footer</h1> {% endblock %} {% block content %} <script> //this is place for javascript </script> {% endblock %} </body> </html>
layout defines five modules, named head, header, body, footer and content. Header and footer are common, so they are basically static. The modification of business code only needs to be done in the body content body, and the business stylesheet and business script need to be introduced in the head and bottom content respectively.
Next, we define a business level view page: home.html
{% extends 'layout.html' %} {% block head %} <link href="home.css"> {% endblock %} {% block body %} <h1>home Page content</h1> {% endblock %} {% block content %} <script src="home.js"></script> {% endblock%}
Final home.html The output is as follows:
<html> <head> <link href="home.css"> </head> <body> <h1>this is header</h1> <h1>home Page content</h1> <h1>this is footer</h1> <script src="home.js"></script> </body> </html>