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)

这次项目基于上面的渲染分两个VUE文件:login.vue和Main.vue,下面会对这两个VUE文件做具体介绍。

//登录页面路由信息
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应用中托管静态资源。
最常用的用法在上面已经介绍过了,关于更细节的参数可参考官方文档


团建回来搬blog内容(2020/1/4 home)