6.项目结构
这部分应该是在刚开始写的,但忘了= =,现在补上吧。
在说这次项目之前先说基于vue-cli搭建的项目结构各个文件的作用,我就从csdn上找了篇文章(点击此处)。光看这些个概念可能有点抽象,结合这次项目我用自己的理解解释一下;这次用的是嵌套显示,主要通过路由里的children属性设置,具体配置如下:
1.入口html文件(index.html)
<div id='app'></div>
<div id='version'>...</div> <!-- 检查浏览器版本 -->
2.入口js文件(main.js)
new Vue({
el: '#app',
router, // 引用router文件夹index.js
components: {App}, // 入口vue文件
template: '<App/>', // 模板将会替换挂载的元素,挂载元素的内容都将被忽略(看下面注释)
store: VuexStore // vuex原型
})
注释:也就是说:template: ‘<App/>’ 表示用<app></app>替换index.html里面的<div id=”app”></div>
3.入口vue文件(App.vue)
<template>
<div id='app'>
<router-view></router-view> <!-- 路由视图组件 -->
</div>
<template>
4.主路由(router/index.js)
这次项目基于上面的
//登录页面路由信息
const loginRouter = {
path:
name:
component: () => import(...)
}
//业务页面路由信息,都是挂载在Main.vue页面里,等同于入口vue的<router-view>
const defindeRouter = { // 错误跳转页面路由
path:
name:
component: Main // import Main from ...引入Main组件,设置children属性设置业务页面路由
children: [{...}]
}
const topbarRouter = { // top栏路由
path:
name:
component: Main
children: [{...}]
}
const sidebarRouter = [ // 具体各个业务页面路由
{
path:
name:
component: Main
children: [{...}]
},
{
path:
name:
component: Main
children: [{...}]
}
]
export const routerConfig = [
loginRouter,
topbarRouter,
defindeRouter,
...sidebarRouter // 解构
]
//导出路由信息,在App.vue文件中引入
5.Main.vue(业务页面都挂载在下面)
<template>
<Header></Header>
<Content>
<router-view></router-view> // 联系上面的children路由信息,都通过这个路由视图显示
</Content>
<Footer></Footer>
</template>
综上所述,所有页面都显示在入口index.html的<div id=’app’>里,main.js创建VUE实例,login和Main作为两个主vue文件,通过App.vue文件的<router-view>路由视图显示,业务页面通过Main.vue的<router-view>的路由视图显示,利用路由children属性把页面挂载在Main.vue上。
7.路由分发
/*
Apache请求数据库的代码
*/
res = db.query('SELECT * from some_table')
res.output()
/*
Nodejs请求数据库的代码
*/
db.query('SELECT * from some_table', function(res){
res.output()
})
由于项目开发的深入,为了配合设备层的配置下发,后台开始着手core层的接口,也就是说不完全针对页面显示的数据接口;这种情况下需要前台对接口进行路由分发,对于后台给出的接口改构和包装,达到页面显示需要的数据结构的接口,这次用的是nodejs的express框架,在应用到项目前,这里算是学习笔记和感想。
一个基本的express应用的结构:
var express = require('express') // 安装node的时候回自动安装express
var app = express()
app.get('/', (req,res) => { // req(请求)和res(响应)与Node提供的对象完全一致
res.send('监听3030端口进入的所有get请求')
})
var server = app.listen(3030, function{
var host = server.address().address
var port = server.address().port
console.log('Example app listening at http://%s:%s', host, port)
})
1.基本路由和静态文件挂载
常见的4个基本http请求:
// 对网站首页的访问返回 "Hello World!" 字样
app.get('/', function (req, res) {
res.send('Hello World!');
});
// 网站首页接受 POST 请求
app.post('/', function (req, res) {
res.send('Got a POST request');
});
// /user 节点接受 PUT 请求
app.put('/user', function (req, res) {
res.send('Got a PUT request at /user');
});
// /user 节点接受 DELETE 请求
app.delete('/user', function (req, res) {
res.send('Got a DELETE request at /user');
});
利用express托管静态文件(express.static中间件)
app.use(express.static('public'))
// 通过http://localhost:3030/image/xx.png访问
// 多个目录按照添加顺序查找
app.use('/public', express.static('public'))
// 存放虚拟目录,通过指定的挂载路径访问:http://localhost:3030/public/image/xx.png
2.路由
路由是指如何定义应用的端点(URIs)以及如何响应客户端的请求。
路由是由一个 URI、HTTP 请求(GET、POST等)和若干个句柄组成,它的结构如下: app.METHOD(path, [callback…], callback), app 是 express 对象的一个实例, METHOD 是一个 HTTP 请求方法, path 是服务器上的路径, callback 是当路由匹配时要执行的函数。
// 对于上面的4种请求的句柄改用app.route()定义链式句柄
app.route('/public')
.get((req,res) => {
...
})
.post((req,res) => {
...
})
.put((req,res) => {
...
});
// 监听来自/public的所有请求
app.all('/public', function(req,res,next){
...
next();
})
// 路由匹配
// 匹配 butterfly、dragonfly,不匹配 butterflyman、dragonfly man等
app.get(/.*fly$/, function(req, res) {
res.send('/.*fly$/');
});
express.Router
调用express()方法创建的Application(app)内部都创建了一个Router,大部分对 Application 的操作实际上都被重定向到了这个内部的Router上而已。而Application所做的,只不过是在这个Router的基础上添加了一些额外的便捷 API 而已。
var express = require('express');
var router = express.Router();
// 该路由使用的中间件
router.use(function timeLog(req, res, next) {
console.log('Time: ', Date.now());
next();
});
// 定义网站主页的路由
router.get('/', function(req, res) {
res.send('Birds home page');
});
// 定义 about 页面的路由
router.get('/about', function(req, res) {
res.send('About public');
});
module.exports = router;
// 在应用中加载路由模块
var pub = require('js文件路径');
...
app.use('/public', pub);
// 应用即可处理发自 /public 和 /public/about 的请求,并且调用为该路由指定的 timeLog 中间件
3.中间件
中间件(Middleware)是一个函数,它可以访问请求对象(request object (req)),响应对象(response object (res)),和 web 应用中处于请求-响应循环流程中的中间件,一般被命名为 next 的变量。
关于next()函数的解释,我找了一篇比较好的文章
中间件的功能包括:
- 执行任何代码;
- 修改请求和响应对象;
- 终结请求-响应循环;
- 调用堆栈中的下一个中间件。
如果当前中间件没有终结请求-响应循环,则必须调用 next()方法将控制权交给下一个中间件,否则请求就会挂起。
Express 应用可使用如下几种中间件:
- 应用级中间件
- 路由级中间件
- 错误处理中间件
- 内置中间件
- 第三方中间件
1.应用级中间件
应用级中间件绑定到app对象使用app.use()和app.METHOD(),其中METHOD是需要处理的HTTP请求的方法,例如GET, PUT, POST 等等,全部小写。例如:
var app = express();
// 没有挂载路径的中间件,应用的每个请求都会执行该中间件
app.use(function (req, res, next) {
console.log('Time:', Date.now());
next();
});
// 挂载至 /user/:id 的中间件,任何指向 /user/:id 的请求都会执行它
app.use('/user/:id', function (req, res, next) {
console.log('Request Type:', req.method);
next();
});
// 路由和句柄函数(中间件系统),处理指向 /user/:id 的 GET 请求
app.get('/user/:id', function (req, res, next) {
res.send('USER');
});
下面这个例子展示了在一个挂载点装载一组中间件。
// 一个中间件栈,对任何指向 /user/:id 的 HTTP 请求打印出相关信息
app.use('/user/:id', function(req, res, next) {
console.log('Request URL:', req.originalUrl);
next();
}, function (req, res, next) {
console.log('Request Type:', req.method);
next();
});
作为中间件系统的路由句柄,使得为路径定义多个路由成为可能。在下面的例子中,为指向 /user/:id 的 GET 请求定义了两个路由。第二个路由虽然不会带来任何问题,但却永远不会被调用,因为第一个路由已经终止了请求-响应循环。
// 一个中间件栈,处理指向 /user/:id 的 GET 请求
app.get('/user/:id', function (req, res, next) {
console.log('ID:', req.params.id);
next();
}, function (req, res, next) {
res.send('User Info');
});
// 处理 /user/:id, 打印出用户 id
app.get('/user/:id', function (req, res, next) {
res.end(req.params.id);
});
如果需要在中间件栈中跳过剩余中间件,调用 next(‘route’) 方法将控制权交给下一个路由。 注意: next(‘route’) 只对使用 app.VERB() 或 router.VERB() 加载的中间件有效。
// 一个中间件栈,处理指向 /user/:id 的 GET 请求
app.get('/user/:id', function (req, res, next) {
// 如果 user id 为 0, 跳到下一个路由
if (req.params.id == 0) next('route');
// 否则将控制权交给栈中下一个中间件
else next(); //
}, function (req, res, next) {
// 渲染常规页面
res.render('regular');
});
// 处理 /user/:id, 渲染一个特殊页面
app.get('/user/:id', function (req, res, next) {
res.render('special');
});
2.路由级中间件
路由级中间件和应用级中间件一样,只是它绑定的对象为 express.Router()。
var router = express.Router();
路由级使用 router.use() 或 router.VERB() 加载。
上述在应用级创建的中间件系统,可通过如下代码改写为路由级:
var app = express();
var router = express.Router();
// 没有挂载路径的中间件,通过该路由的每个请求都会执行该中间件
router.use(function (req, res, next) {
console.log('Time:', Date.now());
next();
});
// 一个中间件栈,显示任何指向 /user/:id 的 HTTP 请求的信息
router.use('/user/:id', function(req, res, next) {
console.log('Request URL:', req.originalUrl);
next();
}, function (req, res, next) {
console.log('Request Type:', req.method);
next();
});
// 一个中间件栈,处理指向 /user/:id 的 GET 请求
router.get('/user/:id', function (req, res, next) {
// 如果 user id 为 0, 跳到下一个路由
if (req.params.id == 0) next('route');
// 负责将控制权交给栈中下一个中间件
else next(); //
}, function (req, res, next) {
// 渲染常规页面
res.render('regular');
});
// 处理 /user/:id, 渲染一个特殊页面
router.get('/user/:id', function (req, res, next) {
console.log(req.params.id);
res.render('special');
});
// 将路由挂载至应用
app.use('/', router);
路由级中间件和非路由级中间件的第三个参数next不是同一个next,功能上基本相同。
3.错误处理中间件
错误处理中间件有 4 个参数,定义错误处理中间件时必须使用这4个参数(4个参数是next(err)执行判断的标识)。即使不需要next对象,也必须在签名中声明它,否则中间件会被识别为一个常规中间件,不能处理错误。
app.use(function(err, req, res, next) {
console.error(err.stack);
res.status(500).send('Something broke!');
});
具体关于错误处理中间件的介绍可以参考官方文档
4.内置中间件
express.static是Express唯一的内置中间件。它基于serve-static,负责在Express应用中托管静态资源。
最常用的用法在上面已经介绍过了,关于更细节的参数可参考官方文档