视频地址:https://www.cctalk.com/v/15114923882788javascript
无非花开花落,静静。css
这里咱们使用第三方中间件: koa-static
html
安装 koa-static
:前端
npm i koa-static -S
修改 app.js
,增长并指定 /public
目录为静态资源目录。java
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') })
以后咱们对项目的视图进行美化,使之更为赏心悦目。git
在 /public/home/
目录下新增样式文件 main.css
,内容以下:github
*{ 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/slogan@2x-3x9xM.png?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/feature-icon1@2x-BvNad.png?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/feature-icon2@2x-1raFv.png); } .feature>.feature-item:nth-child(3) .ico{ background-image: url(https://res.hjfile.cn/cc/cctalk.hujiang.com/home/images/feature-icon3@2x-2y1F0.png); } .feature>.feature-item:nth-child(4) .ico{ background-image: url(https://res.hjfile.cn/cc/cctalk.hujiang.com/home/images/feature-icon4@2x-27VL5.png); } .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
视图文件,按照继承的方式提取出公用部分。web
新建 /views/common/header.html
npm
<header class="header"> <div class="header-box wraper">Node实战教程 | <span class="logo">© iKcamp</span></div> </header>
新建 /views/common/footer.html
json
<footer class="footer"> <div class="footer-box wraper"> <p class="title">沪江Web前端团队倾情奉献</p> <p><a href="https://github.com/ikcamp">https://github.com/ikcamp</a></p> <br> <p class="info">iKcamp由沪江Web前端团队中热爱原创和翻译的小伙伴发起,成立于2016年7月,"iK"表明布兰登·艾克(JavaScript之父)。 追随JavaScript这门语言所秉持的精神,崇尚开放和自由的咱们一同工做、分享、创做,等候更多有趣跳动的灵魂。</p> <p class="police">沪ICP备17041059号 ©2017-2018 </p> </div> </footer>
新建 /views/common/layout.html
。注意,此处有模板变量 title
。
<!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.html
就是咱们的基础页面。如今咱们再为 home
建立专用的 layout-home.html
,并在里面引用以前建立的样式表:
新建 /views/common/layout-home.html
。注意,咱们在 body
模块里又增长了一个 homeBanner
模块:
{% 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">免费资源</h4> <p class="des">为天地立心</p> </li> <li class="feature-item"><i class="ico"></i> <h4 class="tit">体系知识</h4> <p class="des">为科技立命</p> </li> <li class="feature-item"><i class="ico"></i> <h4 class="tit">实战项目</h4> <p class="des">为大牛继绝学</p> </li> <li class="feature-item"><i class="ico"></i> <h4 class="tit">线下交流</h4> <p class="des">为教育开太平</p> </li> </ul> </div> </div> {% endblock %}
公用部分提取完成以后,重写 home
交互页面。此时咱们对登陆功能的视图进行美化,有主页,登陆,以及登陆后的响应页面。
新增 /views/home/index.html
首页
{% extends "common/layout-home.html" %} {% block homeBanner %} <div class="banner_box"> <div class="banner_inner"> <h2 class="slogan">汇聚天下英才</h2> <p class="des">iKcamp是由沪江Web前端团队发起的自由组织<br>咱们追随JavaScript这门语言所秉持的精神,为ITer提供完善的在线学习平台和知识体系</p> <a href="/user" title="gogogo" class="btn" id="gogogo">进入战场</a> </div> </div> {% endblock %}
修改 /views/home/login.html
登陆页面
{% extends "common/layout-home.html" %} {% block homeBanner %} <div class="banner_box"> <div class="banner_inner"> <h2 class="slogan">汇聚天下英才</h2> <p class="des">iKcamp是由沪江Web前端团队发起的自由组织<br>咱们追随JavaScript这门语言所秉持的精神,为ITer提供完善的在线学习平台和知识体系</p> <a href="/login" title="gogogo" class="btn" id="gogogo">进入战场</a> </div> </div> {% endblock %} {% block content %} <div class="hp-dialog"> <div class="hp-box"> <form action="/user/register" method="post"> <h1>到达战场</h1> <p class="error">{{content}}</p> <input type="text" name="name" placeholder="请输入用户名:ikcamp"> <input type="password" name="password" placeholder="请输入密码:123456"> <button>GoGoGo</button> </form> </div> </div> <div class="hp-overlay"></div> {% endblock %}
新增 /views/home/success.html
成功页面
{% extends "common/layout-home.html" %} {% block homeBanner %} <div class="banner_box"> <div class="banner_inner"> <h2 class="slogan">汇聚天下英才</h2> <p class="des">iKcamp是由沪江Web前端团队发起的自由组织<br>咱们追随JavaScript这门语言所秉持的精神,为ITer提供完善的在线学习平台和知识体系</p> <a href="javascript:;" title="gogogo" class="btn" id="gogogo">成功进入战场</a> </div> </div> {% 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
数据传递,错误处理机制,日志记录功能等。
下一篇:提高篇 - 解析JSON——让 Koa2 支持响应 JSON 数据
上一篇:iKcamp新课程推出啦~~~~~iKcamp|基于Koa2搭建Node.js实战(含视频)☞ 视图Nunjucks