vscode配置egg.js
关于egg.js的小贴士:
- app/public文件夹用于放静态资源
- app/service 文件夹用于放数据处理(M)
- app/view 文件夹用于放模板 (V)
- app/controller文件夹用于放业务逻辑处理(C)
- app/middleware 文件夹用于放中间件
- app/extend 文件夹用于存放扩展插件
- koa给用户了一个context对象,egg把它又封装近了this (其实是个Controller)中
- 一个服务可以被多个控制器调用
- 一个服务可以调用另一个 服务
一. 安装egg
首先nodejs大于8.0
cnpm i egg-init -g
https://eggjs.org/
二. 快速初始化
1. 脚手架初始化egg工程
我们推荐直接使用脚手架,只需几条简单指令,即可快速生成项目(npm >=6.1.0):
(非常可能需要翻墙~~cnpm都不好使)
$ mkdir egg-example && cd egg-example
$ npm init egg --type=simple
安装过程中可能会有一些询问, 按需填写
2. 恢复依赖
$ cnpm i
3. 启动项目:
$ npm run dev
$ open http://localhost:7001
4. 工程目录结构
三. 路由
1. 最简单的路由
太简单了,只需要两步
1. 在app/controller/home.js中添加一个
async news() {
const { ctx } = this; //koa给用户了一个context对象,egg把它又封装近了this中 (其实是个Controller)
ctx.body = 'hi, news';
}
2. 在app/router.js中添加get方法
router.get('/news', controller.home.news);
2. 获取get传值 this.ctx.query
this.ctx.query
3. 动态路由 this.ctx.params
在router.js中设置一个动态路由
router.get('/newslist/:id',controller.news.newslist)
访问时需要传入动态路由值http://127.0.0.1:7001/newslist/123
如何获取动态路由参数?
async newslist() {
this.ctx.body = this.ctx.params
}
四. 模板引擎 ejs
cnpm i egg-view-ejs --save
1. 配置ejs
// {app_root}/config/plugin.js
'use strict';
exports.ejs = {
enable: true,
package: 'egg-view-ejs',
};
// {app_root}/config/config.default.js
config.view = {
mapping: {
'.html': 'ejs',
}
}
2. 使用
// app/view/hello.html
hello <%= data %>
Render it
// app/controller/render.js
exports.ejs = async ctx => {
await ctx.render('hello', {
data: 'world',
});
};
//news.js
class NewsController extends Controller {
async index() {
await this.ctx.render('hello',{
data:1
})
}
}
ejs语法请参考https://www.jianshu.com/p/1a7e01d41801
ejs
五 静态资源
egg.js中的静态资源不需要声明,直接访问
http://127.0.0.1:7001/public/1.jpg
六 配置公共参数
在config.default.js中
例如;我们配置了
config.api="http://www.phonegap100.com"
那么在任何地方,我们都可以用this.config.api 来调用得到这个字符串
七. 控制器Controller
1. 控制器的this
定义的 Controller 类,会在每一个请求访问到 server 时实例化一个全新的对象,而项目中的 Controller 类继承于 egg.Controller
,会有下面几个属性挂在 this
上。
-
this.ctx
: 当前请求的上下文 Context 对象的实例,通过它我们可以拿到框架封装好的处理当前请求的各种便捷属性和方法。 -
this.app
: 当前应用 Application 对象的实例,通过它我们可以拿到框架提供的全局对象和方法。 -
this.service
:应用定义的 Service,通过它我们可以访问到抽象出的业务层,等价于this.ctx.service
。 -
this.config
:应用运行时的配置项。 -
this.logger
:logger 对象,上面有四个方法(debug
,info
,warn
,error
),分别代表打印四个不同级别的日志,使用方法和效果与 context logger 中介绍的一样,但是通过这个 logger 对象记录的日志,在日志前面会加上打印该日志的文件路径,以便快速定位日志打印位置。
2.
八. 服务Service
1. 服务的this
每一次用户请求,框架都会实例化对应的 Service 实例,由于它继承于 egg.Service
,故拥有下列属性方便我们进行开发:
-
this.ctx
: 当前请求的上下文 Context 对象的实例,通过它我们可以拿到框架封装好的处理当前请求的各种便捷属性和方法。 -
this.app
: 当前应用 Application 对象的实例,通过它我们可以拿到框架提供的全局对象和方法。 -
this.service
:应用定义的 Service,通过它我们可以访问到其他业务层,等价于this.ctx.service
。 -
this.config
:应用运行时的配置项。 -
this.logger
:logger 对象,上面有四个方法(debug
,info
,warn
,error
),分别代表打印四个不同级别的日志,使用方法和效果与 context logger 中介绍的一样,但是通过这个 logger 对象记录的日志,在日志前面会加上打印该日志的文件路径,以便快速定位日志打印位置。
2.服务的命名规则
Service 文件必须放在 app/service 目录,可以支持多级目录,访问的时候可以通过目录名级联访问。
app/service/biz/user.js => ctx.service.biz.user
app/service/sync_user.js => ctx.service.syncUser
app/service/HackerNews.js => ctx.service.hackerNews
3. 服务的创建和访问
我们在service下建立一个news.js来提供数据服务
'use strict';
const Service = require('egg').Service;
class NewsService extends Service {
async getlist() {
//获取新闻数据
return [111,222,333,888]
}
}
module.exports = NewsService;
在控制器中,我们可以使用这个服务this.service.news.具体服务
'use strict';
const Controller = require('egg').Controller;
class NewsController extends Controller {
async index() {
let list1=await this.service.news.getlist()
await this.ctx.render('news',{
data:1,
list1
})
}
}
module.exports = NewsController;
八. 用this.ctx.curl(url)请求数据
九. 扩展 extend
框架提供了多种扩展点扩展自身的功能:
- Application
- Context
- Request
- Response
- Helper 工具方法
在开发中,我们既可以使用已有的扩展 API 来方便开发,也可以对以上对象进行自定义扩展,进一步加强框架的功能。
如果想扩展哪个东西,就要在app/extend文件夹中新建xxx.js 比如:app/extend/context.js
比如:我们新建一个方法让时间戳转化为时间
新建app/extend/application.js, 框架会把 app/extend/application.js 中定义的对象与 Koa Application 的 prototype 对象进行合并,在应用启动时会基于扩展后的 prototype 生成 app 对象。
方法扩展
例如,我们要增加一个 app.foo()
方法:
module.exports = {
foo(param) {
// this 就是 app 对象,在其中可以调用 app 上的其他方法,或访问属性
},
};
属性扩展
一般来说属性的计算只需要进行一次,那么一定要实现缓存,否则在多次访问属性时会计算多次,这样会降低应用性能。
推荐的方式是使用 Symbol + Getter 的模式。
例如,增加一个 app.bar
属性 Getter:
// app/extend/application.js
const BAR = Symbol('Application#bar');
module.exports = {
get bar() {
// this 就是 app 对象,在其中可以调用 app 上的其他方法,或访问属性
if (!this[BAR]) {
// 实际情况肯定更复杂
this[BAR] = this.config.xx + this.config.yy;
}
return this[BAR];
},
};