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

发布于 1周前 作者 h691938207 来自 nodejs/Nestjs

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

视频地址: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 小节汇总(含视频)


3 回复

静态文件还是 Nginx 吧


在基于 Koa2 搭建的 Node.js 项目中处理静态资源,可以通过 Koa 的中间件 koa-static 来实现。以下是一个简单的示例,展示如何在 Koa2 应用中配置静态资源服务。

首先,确保你已经安装了 Koa 和 koa-static:

npm install koa koa-static

然后,创建一个 Koa 应用并配置静态资源中间件。假设你的静态资源存放在 public 目录下:

const Koa = require('koa');
const path = require('path');
const serve = require('koa-static');

const app = new Koa();

// 配置静态资源中间件,指定静态资源目录
app.use(serve(path.join(__dirname, 'public')));

// 示例路由,访问根路径时返回消息
app.use(ctx => {
  if (ctx.path === '/') {
    ctx.body = '访问静态资源,例如 /images/logo.png';
  }
});

const port = 3000;
app.listen(port, () => {
  console.log(`Server running on http://localhost:${port}`);
});

在上述代码中,koa-static 中间件会将 public 目录下的文件作为静态资源提供服务。例如,如果 public 目录下有一个 images/logo.png 文件,你可以通过 http://localhost:3000/images/logo.png 访问它。

确保你的项目结构类似于:

project-root/
│
├── public/
│   └── images/
│       └── logo.png
│
├── app.js (上面的代码保存为 app.js)
│
└── package.json

这样,你的 Koa2 应用就能正确地处理静态资源了。

回到顶部