iKcamp|基于 Koa2 搭建 Node.js 实战(含视频) 处理静态资源 - V2EX
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
iKcamp
V2EX    Node.js

iKcamp|基于 Koa2 搭建 Node.js 实战(含视频) 处理静态资源

  •  
  •   iKcamp 2018-01-12 11:14:09 +08:00 3243 次点击
    这是一个创建于 2878 天前的主题,其中的信息可能已经有所发展或是发生改变。

    视频地址:https://www.cctalk.com/v/15114923882788

    处理静态资源

    无非花开花落,静静。


    指定静态资源目录

    这里我们使用第三方中间件: 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

     <header class="header"> <div class="header-box wraper">Node 实战教程 | <span class="logo"> iKcamp</span></div> </header> 

    新建 /views/common/footer.html

     <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 交互页面。此时我们对登录功能的视图进行美化,有主页,登录,以及登录后的响应页面。


    重写 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 的处理逻辑进行修改


    重写 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 中的 indexregister 方法:

     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

    推荐: 翻译项目 Master 的自述:

    1. 干货|人人都是翻译项目的 Master

    2. iKcamp 出品微信小程序教学共 5 章 16 小节汇总(含视频)

    2 条回复    2018-01-27 12:55:06 +08:00
    qinming101
        1
    qinming101  
       2018-01-24 10:49:56 +08:00
    静态文件还是 Nginx 吧
    strugglexiang
        2
    strugglexiang  
       2018-01-27 12:55:06 +08:00
    留下脚步
    关于     帮助文档     自助推广系统     博客     API     FAQ     Solana     2237 人在线   最高记录 6679       Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 25ms UTC 01:05 PVG 09:05 LAX 17:05 JFK 20:05
    Do have faith in what you're doing.
    ubao msn snddm index pchome yahoo rakuten mypaper meadowduck bidyahoo youbao zxmzxm asda bnvcg cvbfg dfscv mmhjk xxddc yybgb zznbn ccubao uaitu acv GXCV ET GDG YH FG BCVB FJFH CBRE CBC GDG ET54 WRWR RWER WREW WRWER RWER SDG EW SF DSFSF fbbs ubao fhd dfg ewr dg df ewwr ewwr et ruyut utut dfg fgd gdfgt etg dfgt dfgd ert4 gd fgg wr 235 wer3 we vsdf sdf gdf ert xcv sdf rwer hfd dfg cvb rwf afb dfh jgh bmn lgh rty gfds cxv xcv xcs vdas fdf fgd cv sdf tert sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf shasha9178 shasha9178 shasha9178 shasha9178 shasha9178 liflif2 liflif2 liflif2 liflif2 liflif2 liblib3 liblib3 liblib3 liblib3 liblib3 zhazha444 zhazha444 zhazha444 zhazha444 zhazha444 dende5 dende denden denden2 denden21 fenfen9 fenf619 fen619 fenfe9 fe619 sdf sdf sdf sdf sdf zhazh90 zhazh0 zhaa50 zha90 zh590 zho zhoz zhozh zhozho zhozho2 lislis lls95 lili95 lils5 liss9 sdf0ty987 sdft876 sdft9876 sdf09876 sd0t9876 sdf0ty98 sdf0976 sdf0ty986 sdf0ty96 sdf0t76 sdf0876 df0ty98 sf0t876 sd0ty76 sdy76 sdf76 sdf0t76 sdf0ty9 sdf0ty98 sdf0ty987 sdf0ty98 sdf6676 sdf876 sd876 sd876 sdf6 sdf6 sdf9876 sdf0t sdf06 sdf0ty9776 sdf0ty9776 sdf0ty76 sdf8876 sdf0t sd6 sdf06 s688876 sd688 sdf86