无非花开花落,静静。
这里我们使用第三方中间件: koa-static
安装 koa-static
:
npm i koa-static -S
修改 app.js
,增加并指定 /public
目录为静态资源目录。
const Koa = require('koa') const path = require('path') const bodyParser = require('koa-bodyparser') const nunjucks = require('koa-nunjucks-2') // 引入 koa-static const staticFiles = require('koa-static') const app = new Koa() const router = require('./router') // 指定 public目录为静态资源目录,用来存放 js css images 等 app.use(staticFiles(path.resolve(__dirname, "./public"))) app.use(nunjucks({ ext: 'html', path: path.join(__dirname, 'views'), nunjucksConfig: { trimBlocks: true } })); app.use(bodyParser()) router(app) app.listen(3000, () => { console.log('server is running at http://localhost:3000') })
之后我们对项目的视图进行美化,使之更为赏心悦目。
在 /public/home/
目录下新增样式文件 main.css
,内容如下:
*{ padding: 0; margin: 0; } body,html{ font-size: 14px; color: #000; background: #fff; font-family: Helvetica Neue,Helvetica,Segoe UI,Arial,Hiragino Sans GB,Microsoft YaHei; -webkit-font-smoothing: antialiased; position: relative; } .fn-clear:after { visibility: hidden; display: block; font-size: 0; content: " "; clear: both; height: 0 } .fn-clear { zoom:1} a { color: #0366d6; text-decoration: none; } a:hover { text-decoration: none; } .header{ width: 100%; background-color: #474747; } .header-box{ height: 30px; line-height: 30px; font-size: 12px; letter-spacing: 2px; color: #d5d5d5; transition: color .3s; } .header-box>.logo{ letter-spacing: 0; font-size: 12px; } .wraper{ width: 1200px; margin: 0 auto; } .container{ min-height: 500px; padding: 80px 0; } .footer{ background: #262a30; padding: 50px 0; border-top: 1px solid #ddd; color: #999; font-size: 16px; } .footer-box{ width: 800px; margin: 0 auto; text-align: center; } .banner_box{ width: 100%; min-width: 1200px; height: 438px; background: url(https://res.hjfile.cn/cc/cctalk.hujiang.com/home/images/banner-2QEtv.jpg?2QEtv) 50% no-repeat; background-size: cover; } .banner_box>.banner_inner{ width: 1200px; margin: 0 auto; padding-top: 112px; } .banner_inner>.slogan{ width: 427px; height: 54px; background: url(https://res.hjfile.cn/cc/cctalk.hujiang.com/home/images/[email protected]?3x9xM); background-size: 100% auto; margin: 0 auto 25px; text-indent: -99999rem; } .banner_inner>.des{ margin-bottom: 24px; font-size: 16px; line-height: 1.9; color: #fff; text-align: center; } .banner_inner>.btn{ display: block; margin: 0 auto; width: 220px; height: 48px; font-size: 20px; line-height: 48px; border-radius: 4px; background-color: #15a9ff; color: #fff; text-align: center; text-decoration: none; box-shadow: 0 2px 6px rgba(0,0,0,.3); } .show_time>.feature-con{ background: #fff; border-bottom: 2px solid #f8f8f8; min-width: 1200px; } .feature-con>.feature{ list-style: none; margin: 0 auto; padding: 40px 0 60px; width: 1200px; } .feature>.feature-item{ float: left; width: 160px; margin: 0; padding: 0; margin-right: 132px; } .feature>.feature-item:first-child{ margin-left: 88px; } .feature>.feature-item:last-child{ margin-right: 0; } .feature .ico{ display: inline-block; width: 160px; height: 130px; background: url(https://res.hjfile.cn/cc/cctalk.hujiang.com/home/images/[email protected]?BvNad); background-size: 100% auto; } .feature>.feature-item:nth-child(2) .ico{ background-image: url(https://res.hjfile.cn/cc/cctalk.hujiang.com/home/images/[email protected]); } .feature>.feature-item:nth-child(3) .ico{ background-image: url(https://res.hjfile.cn/cc/cctalk.hujiang.com/home/images/[email protected]); } .feature>.feature-item:nth-child(4) .ico{ background-image: url(https://res.hjfile.cn/cc/cctalk.hujiang.com/home/images/[email protected]); } .feature-item>.tit{ padding: 0; margin: 0; font-size: 16px; line-height: 26px; color: #333; text-align: center; font-weight: 400; } .feature-item>.des{ padding: 0; margin: 0; font-size: 16px; line-height: 26px; color: #333; text-align: center; opacity: .5; } .hp-overlay{ position: absolute; left: 0; top: 0; width: 100%; height: 100%; z-index: 99999; opacity: .5; filter: Alpha(opacity=50); background-color: #000; } .hp-dialog{ width: 370px; border-radius: 5px; background-color: #fff; outline: 0; box-shadow: 0 5px 30px rgba(0,0,0,.2); z-index: 1000000; position: fixed; left: 50%; top: 50%; -webkit-transform: translate(-50%,-50%); -ms-transform: translate(-50%,-50%); transform: translate(-50%,-50%); } .hp-box{ padding: 12px 30px 30px; color: #333; } .hp-box h1{ line-height: 48px; text-align: center; font-size: 20px; font-weight: 400; margin-bottom: 12px; } .hp-box .error{ color: red; line-height: 30px; } .hp-box input{ display: block; width: 100%; height: 42px; padding: 10px 10px 10px 10px; border-radius: 3px; border: 1px solid #e5e5e5; font-size: 14px; line-height: 20px; outline: 0; -webkit-appearance: none; appearance: none; -webkit-transition: border .2s ease; transition: border .2s ease; margin-bottom: 30px; box-sizing: border-box; } .hp-box button{ display: block; width: 100%; height: 42px; background-color:#44b336; border: 0; border-radius: 3px; color: #fff; font-size: 18px; line-height: 42px; text-align: center; outline: 0; cursor: pointer; } .hp-box input:focus,.hp-box input:focus:hover { border: 1px solid #44b336 } .hp-box input:hover { border: 1px solid #ddd } .hp-box input::-webkit-input-placeholder { color: #ddd } .hp-box input::-ms-input-placeholder { color: #ddd } .hp-box input::-ms-reveal { display: none } .hp-box input::-ms-clear { display: none } .footer .title{ font-size: 24px; } .footer .info{ letter-spacing: 2px; }
然后修改 views
视图文件,按照继承的方式提取出公用部分。
新建 /views/common/header.html
Node实战教程 | © iKcamp
新建 /views/common/footer.html
新建 /views/common/layout.html
。注意,此处有模板变量 title
。
{{title}} {% block head %} {% endblock %} {% include "./header.html" %} {% block body %} {% endblock %} {% include "./footer.html" %} {% block content %} {% endblock %}
layout.html
就是我们的基础页面。现在我们再为 home
创建专用的 layout-home.html
,并在里面引用之前创建的样式表:
新建 /views/common/layout-home.html
。注意,我们在 body
模块里又增加了一个 homeBanner
模块:
{% extends "./layout.html" %} {% block head %} {% endblock %} {% block body %} {% block homeBanner %} {% endblock %}{% endblock %}
免费资源
为天地立心
体系知识
为科技立命
实战项目
为大牛继绝学
线下交流
为教育开太平
公用部分提取完成之后,重写 home
交互页面。此时我们对登录功能的视图进行美化,有主页,登录,以及登录后的响应页面。
新增 /views/home/index.html
首页
{% extends "common/layout-home.html" %} {% block homeBanner %}{% endblock %}
修改 /views/home/login.html
登录页面
{% extends "common/layout-home.html" %} {% block homeBanner %}{% endblock %} {% block content %}{% endblock %}
新增 /views/home/success.html
成功页面
{% extends "common/layout-home.html" %} {% block homeBanner %}{% endblock %}
增加完成后,需要对 home
的处理逻辑进行修改
修改 /service/home.js
module.exports = { register: async function(name, pwd) { let data if(name == 'ikcamp' && pwd == '123456'){ data = { status: 0, data: { title: "个人中心", content: "欢迎进入个人中心" } } }else{ data = { status: -1, data: { title: '登录失败', content: "请输入正确的账号信息" } } } return data } }
修改 /controller/home.js
中的 index
和 register
方法:
const HomeService = require("../service/home") module.exports = { // 修改 index 方法 index: async function (ctx, next) { await ctx.render("home/index", {title: "iKcamp欢迎您"}) }, // 修改 register 方法 register: async function (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 = "个人中心" await ctx.render("home/success", res.data) } } }
运行代码,并通过浏览器访问 localhost:3000
:
点击进入战场
验证失败
验证成功
目前,项目的基本功能都已完善。结构目录如下:
├── 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
在后面的章节中,我们将进一步完善其他功能,例如 JSON
数据传递,错误处理机制,日志记录功能等。
原文https://github.com/ikcamp/koa2-tutorial/tree/6-static