likes
comments
collection
share

前端全栈框架 - Express 安装与使用 - 《手把手带你从零开始学全栈》

作者站长头像
站长
· 阅读数 23

前端全栈框架 -  Express 安装与使用  - 《手把手带你从零开始学全栈》

Express 是一个精简、灵活的Node.js的Web应用程序开发框架,为Web和移动应用程序提供了一组强大的功能;简单来说,Express 框架本身是对Node.js中的HTTP模块进行的一层抽象,就是这层抽象使得开发者可以无须注意细节,直接上手进行页面和业务逻辑的开发

一个合格的工程从来不是一些简单的文件堆砌,就如同建造一座摩天大楼一样,并不像搭建一个玩具模型的房子,通过简单的拼装就可以完成;建造一座摩天大楼必须拥有坚实的地基和框架,还要有规范和章程才能完成;Express框架从Node.js发布之初就存在,至今已有十多年的历史了;开发者可以使用Express快速地搭建一个具有完整功能的网站,而不是一个简单的网页

Express 的主要功能包括:

  • 设置中间件来响应HTTP请求
  • 定义路由表执行不同的HTTP请求动作
  • 通过向模板传递参数动态渲染HTML页面

1. Express 的安装

要安装Express,首先要具备Node.js环境;安装node.js环境的方法这里不再介绍,请自行查找搭建即可;检查电脑是否安装node的方法,在终端里面输入命令行: node -v 回车,即可

node -v

然后输入命令行:npm install -g express 回车

npm install -g express

npm命令运行完毕,可以运行以下命令查看Express的版本号,如果出现则证明Express已经安装成功

express --version

在安装完Express之后,就可以使用Express命令来创建一个新的项目了

2. 使用Express创建项目

以下以 Mac 系统为例

(1) 桌面新建 demo 文件夹

前端全栈框架 -  Express 安装与使用  - 《手把手带你从零开始学全栈》

(2) 打开终端,输入 cd ,然后将demo文件夹拖拽进终端内

前端全栈框架 -  Express 安装与使用  - 《手把手带你从零开始学全栈》

(3) 执行创建命令,创建一个名为hello的Express项目

express hello

(4) 创建成功之后会在demo目录下出现一个名叫hello的目录,进入hello目录,然后安装依赖包

npm install

(5) 安装完毕后,执行命令启动应用

npm start

(6) 应用启动后,在浏览器中输入http://localhost:3000/ 网址就可以看到应用了

前端全栈框架 -  Express 安装与使用  - 《手把手带你从零开始学全栈》

3. Express 项目结构分析

项目正常启动后,我们使用 vsCode 打开hello项目看一下它的目录结构,如图所示

前端全栈框架 -  Express 安装与使用  - 《手把手带你从零开始学全栈》

看起来是不是结构比较简单?相比较其他语言的框架来说很轻量,这也是Node.js快速开发的一个特色

目录结构中的文件及其作用如下表所示

目录名/文件名类型作用
bin目录服务器脚本默认目录
bin / wwwjs服务器默认脚本,即启动服务脚本
node_modules目录依赖包安装目录,用于存放依赖包
public目录静态资源目录,用于存放静态资源
routes目录路由目录,用于存放路由文件
routes / indexjs首页路由文件
routes / usersjs用户路由文件
views目录页面目录,用于存放页面文件
views / errorjade错误页面
views / indexjade首页
views / layoutjade页面共用布局
appjs应用主文件
packagejson项目配置文件
package-lockjson锁定的项目配置文件

下面我们重点给 app.js 添加一些注释分析,因为 app.js 文件相当于项目启动的主入口文件,有一些公共方法和服务器配置等信息

// http 处理模块
var createError = require('http-errors');
// 引入 Express
var express = require('express');
// 引入 path
var path = require('path');
// 引入 cookie 处理对象
var cookieParser = require('cookie-parser');
// 引入日志模块
var logger = require('morgan');

// 引入路由文件中的 index.js 文件
var indexRouter = require('./routes/index');
// 引入路由文件中的 users.js 文件
var usersRouter = require('./routes/users');

// 创建 Express 应用
var app = express();

// 定义页面目录
app.set('views', path.join(__dirname, 'views'));
// 定义页面模板引擎
app.set('view engine', 'jade');

// 定义日志打印级别
app.use(logger('dev'));
// 定义 JSON 格式处理数据
app.use(express.json());
// 定义使用 urlencoded 处理数据及 querystring 模块解析数据
app.use(express.urlencoded({ extended: false }));
// 定义使用 cookie 处理对象
app.use(cookieParser());
// 定义静态资源目录 public
app.use(express.static(path.join(__dirname, 'public')));
// 定义指向 index.js 的路由
app.use('/', indexRouter);
// 定义指向 user.js 的路由
app.use('/users', usersRouter);

// 定义 404 错误处理
app.use(function(req, res, next) {
  next(createError(404));
});

// 定义其他错误处理
app.use(function(err, req, res, next) {
  // 设置 locals ,只在开发环境生效
  res.locals.message = err.message;
  res.locals.error = req.app.get('env') === 'development' ? err : {};

  // 返回错误 http 状态码
  res.status(err.status || 500);
  // 渲染错误页面
  res.render('error');
});

module.exports = app;

4. Express 路由

接触到一款框架,首先要熟悉的就是它的路由;路由是指应用程序的端点(URI)如何响应客户端请求

通俗来说,就是定义什么路径来访问

4-1. GET 请求路由

在Express中定义路由特别简单。首先来看一下routes目录中的index.js路由文件,也就是首页路由文件,它是一个GET请求路由,如下:

// 引入 Express
var express = require('express');
// 引入 Express 路由对象
var router = express.Router();

// 首页路由
router.get('/', function(req, res, next) {
  res.render('index', { title: 'Express' });
});

// 导出路由
module.exports = router;

首页路由文件很简单,其中也只定义了一个根目录的路由

将其中的代码:

 res.render('index', { title: 'Express' });

更换成如下代码:

res.render('index', { title: Hello });

保存文件,重新运行 npm start 命令,用浏览器打开 http://localhost:3000 查看效果,因为在浏览器地址栏中输入地址发送的请求默认是GET请求

前端全栈框架 -  Express 安装与使用  - 《手把手带你从零开始学全栈》

可以看到,之前的Express被换成了Hello

前面的一段代码定义了首页的路由,这个路由定义的是GET请求,请求的是“/”路径,也就是根路径;接着后面跟着一个方法,当用户发送GET请求根路径的时候,就进入这个方法中,在这个方法中可以进行一些对请求的操作

Express默认的首页方法中使用了res.render()方法,该方法的作用是渲染页面;其第一个参数就是页面的文件名,这里对应的就是views目录中的index.jade文件;第二个参数是传入到页面文件的对象,可以将数据渲染到页面上

4-2. 自定义路由

分析过首页路由之后,可以试着自己写一个路由;在index.js路由文件中添加如下代码:

// 定义一个GET请求“/world”的路由,执行方法
router.get('/world', function (req, res, next) {
  // 渲染index页面
  res.render('index', { title: 'Hello World' });
});

将项目重新 npm start 启动,打开浏览器请求地址 http://localhost:3000/world

前端全栈框架 -  Express 安装与使用  - 《手把手带你从零开始学全栈》

新定义的路由生效了,是不是很简单呢?

但是每次更改过路由文件都要重新启动项目才会生效,是不是觉得太麻烦太影响效率了?

4-3. nodemon 工具使用

在这里,给大家推荐一个工具 nodemon ,其安装方式也是利用npm命令:

npm install -g nodemon

安装完成之后,修改项目根目录中的 package.json 文件,将其中的

  "scripts": {
    "start": "node ./bin/www"
  },

修改成:

 "scripts": {
    "start": "nodemon ./bin/www"
  },

然后再执行 npm start 命令启动项目,这样在路由文件被更改并保存之后,会自动重启项目,并可以立刻在浏览器中看到更改后的运行结果


🔔 nodemon 安装小提示

安装完 nodemon 后运行执行 npm start 命令启动项目如果出现下方错误

前端全栈框架 -  Express 安装与使用  - 《手把手带你从零开始学全栈》

请按顺序执行以下代码

npm uninstall nodemon

sudo npm install -g --force nodemon

4-4. 其他请求方式的路由

HTTP请求方式除了GET之外,还有POST、PUT等其他方式;类似于GET请求的路由编写方式,其他请求方式也换成相应的 router 方法,如下:

// POST请求方式
router.post('/world', function (req, res, next) {
  res.render('index', { title: 'Hello World' });        
});
// PUT请求方式
router.put('/world', function (req, res, next) {
  res.render('index', { title: 'Hello World' });       
});
// DELETE请求方式
router.delete('/world', function (req, res, next) {
  res.render('index', { title: 'Hello World' });       
});

大家可以自己尝试一下相应的请求方式

4-5. 路由匹配规则

前面演示的路由匹配都是完整匹配,即定义“/world”,在浏览器中要输入“/world”才能匹配到

在Express中,除了完整匹配,还支持模糊匹配,例如:

router.get('/wes?t', function (req, res, next) {
  res.render('index', { title: 'Hello West' });
});

会发现当请求 http://localhost:3000/westhttp://localhost:3000/wet 时都可以成功

同样,模糊匹配还可以按如下处理:

能够匹配 /west/weest/weeest

router.get('/we+st', function (req, res, next) {
  res.render('index', { title: 'Hello World' });
})

能够匹配 /west/wt

router.get('/w(es)? t', function (req, res, next) {
  res.render('index', { title: 'Hello World' });
})

能够匹配 /west/we123st/wexxxst

router.get('/we*st', function (req, res, next) {
  res.render('index', { title: 'Hello World' });
})

能够匹配 /west/we123st/wexxxst

router.get('/we*st', function (req, res, next) {
  res.render('index', { title: 'Hello World' });
})

同时,Express路由还支持正则表达式,如下:

// 能够匹配路径中包含west的任何内容,如 /west、/aawest、/westee 等
router.get(/west/, function (req, res, next) {
  res.render('index', { title: 'Hello World' });
})

4-6. 响应方法

下表中响应对象 res 的方法可以向客户机发送响应,并终止请求/响应循环;如果没有从路由处理程序调用其中任何方法,客户机请求将保持挂起状态

方法描述
res.download()提示将要下载文件
res.end()结束响应进程
res.json()发送 JSON 响应
res.jsonp()在 JSONP 的支持下发送 JSON 响应
res.redirect()重定向请求
res.render()呈现视图模板
res.send()发送各种类型的响应
res.sendFile()以八位元流形式发送文件
res.sendStatus()设置响应状态码并以响应主体形式发送其字符串表示

5. Express 页面

在前面定义路由的时候,用到的处理方法中有这么一行代码:

res.render('index', { title: 'Hello World' });

这行代码是Express的返回对象 Response 的一个 render() 方法,这个后面会讲

这里先来讲render()方法的第一个参数,也就是需要渲染的模板文件名,也就是对应views目录中的文件,即页面文件

在前面分析项目结构的时候已经说过,页面目录中有3个页面文件:index.jadeerror.jadelayout.jade;大家可能对 jade 这样的拓展名文件不太熟悉,其实它就是一种模板引擎,为了使用大家熟悉的HTML结构,通常在项目实际开发过程中会将其更换成便于理解的其他模板引擎,比如 art-template

5-1. 更换引擎模板

Express默认的模板引擎是 jade ,为了便于新用户上手开发,需要把它替换成更简洁、高效的 art-template

更换模板引擎的方法也很简单,首先需要安装 art-template 依赖包,分别执行以下命令:

npm install -S art-template 

npm install -S express-art-template

两个依赖包都安装成功之后,修改项目根目录下的 app.js 文件,将其中的

// 定义页面模板引擎
app.set('view engine', 'jade');
```index

更换成


```js
// 定义页面模板引擎
// app.set('view engine', 'jade');

// 更换模板引擎成 art-template
app.engine('.html', require('express-art-template'));
app.set('view engine', 'html');

接着到 views 目录下新建一个 index.html 文件,如下:

<html lang="en">
  <head>
    <meta charset="UTF-8">
    <title>Kylin Technical Team</title>
  </head>
  <body>
    <h3>《手把手带你从零开始学全栈 - Node. + Express + Vue 企业级开发实战》</h3>
  </body>
</html>

然后去浏览器中预览一下效果,模板引擎已经更换成功

前端全栈框架 -  Express 安装与使用  - 《手把手带你从零开始学全栈》

5-2. 渲染数据到页面上

目前的大前端,基本所有数据都是动态生成的;在前面的章节中说过,在Express中将数据渲染到页面上的方法是response 对象的 render() 方法的第二个参数,如下:

// 定义一个GET请求“/”的路由
router.get('/', function (req, res, next) {
  // 渲染index页面,并传送变量title
  res.render('index', { title: 'Hello' });
});

这段代码在渲染的时候向 index.html 页面中传入了一个值为 Hellotitle 字段,但是在浏览器中预览却没有看到这个 Hello,这是因为还没有编辑页面文件来接收这个 title 字段

打开 views 目录中的 index.html 文件,在其中的<body></body>标签中添加以下代码:

 <h4>这是设置的 Title 的值 : {{title}}</h4>

在浏览器中预览,效果如图所示

前端全栈框架 -  Express 安装与使用  - 《手把手带你从零开始学全栈》

还可以多定义一些参数,让页面来接收,如下:

// 定义一个GET请求“/”的路由
router.get('/', function (req, res, next) {
  // 渲染index页面,传入对象
  res.render('index', {
    title: 'Hello',
    team: 'Kylin Technical Team',
    name: '黄勇超',
    age: 18
  });
});

修改对应的页面文件 index.html

<html lang="en">

  <head>
    <meta charset="UTF-8">
    <title>Kylin Technical Team</title>
  </head>

  <body>
    <h3>《手把手带你从零开始学全栈 - Node. + Express + Vue 企业级开发实战》</h3>
    <h4>这是设置的 Title 的值 : {{title}}</h4>
    <h4>大家好,我是 {{team}} 的 {{name}},我{{age}}岁了 </h4>
  </body>

</html>

效果图如下

前端全栈框架 -  Express 安装与使用  - 《手把手带你从零开始学全栈》

现在已经能够做到将数据渲染到页面上了,但是在实际开发需求中,必不可少地会根据不同的情况展示不同的页面,这个时候就需要用条件渲染了

5-3. 基本条件渲染

还是基于之前的示例,现在需要实现:

如果我的年龄大于等于30岁,就不展示“我今年XX岁了”这些文字,如果小于30岁,则展示文字

index.js 的路由代码修改为:

// 定义一个GET请求“/”的路由
router.get('/', function (req, res, next) {
  // 渲染index页面,传入对象
  res.render('index', {
    title: 'Hello',
    team: 'Kylin Technical Team',
    name: '黄勇超',
    age: 25
  });
});

将对应的 index.html 页面文件修改为:

<! DOCTYPE html>
  <html lang="en">
  <head>
    <meta charset="UTF-8">
    <title>Title</title>
  </head>
  <body>
    <h2>{{title}}</h2>
    
    <! -- 判断年龄小于30-->
      {{if age<30 }} 
      <p>大家好,我是{{name}},我今年{{age}}岁,很高兴认识大家!</p>
      
      {{/if}}
      
      <! -- 判断年龄大于等于30-->
      {{if age>=30 }}
      <p>大家好,我是{{name}},很高兴认识大家!</p>
      
      {{/if}}
       
  </body>
  </html>

页面效果如下

前端全栈框架 -  Express 安装与使用  - 《手把手带你从零开始学全栈》

现在还是显示年龄的,将路由代码修改为:

// 定义一个GET请求“/”的路由
router.get('/', function (req, res, next) {
  // 渲染index页面,传入对象
  res.render('index', {
    title: 'Hello',
    team: 'Kylin Technical Team',
    name: '黄勇超',
    age: 32
  });
});

再看看效果图

前端全栈框架 -  Express 安装与使用  - 《手把手带你从零开始学全栈》

这时就不会显示年龄了,因为页面文件中的那段条件渲染代码生效了

art-template 中,如上述示例,if 判断有固定的写法,用{{if CONDITION}}开头,以{{/if}}结尾,将需要判断的代码放在其中

5-4. 嵌套条件渲染

除了基本的条件渲染外,很多时候往往存在复杂的情形,需要进行多层判断

art-template也提供了嵌套条件渲染的方式,在条件判断里继续增加条件判断,即嵌套if判断,将页面文件代码更改如下:

<! DOCTYPE html>
  <html lang="en">
  <head>
    <meta charset="UTF-8">
    <title>Title</title>
  </head>
  <body>
    <h2>{{title}}</h2>
    <! -- 判断年龄小于30-->
      {{if age<30 }} <p>大家好,我是{{name}},我今年{{age}}岁,很高兴认识大家!</p>
        {{/if}}
        <! -- 判断年龄大于等于30-->
          {{if age>=30 }}
          <p>大家好,我是{{name}},
            <! -- 判断happy字段是否为真 -->
              {{if happy }}
              <span>很高兴认识大家!</span>
              {{/if}}
          </p>
          {{/if}}
  </body>
  </html>

路由修改如下

// 定义一个GET请求“/”的路由
router.get('/', function (req, res, next) {
  // 渲染index页面,传入对象
  res.render('index', {
    title: 'Hello',
    team: 'Kylin Technical Team',
    name: '黄勇超',
    age: 42,
    happy:false
  });
});

这样页面又发生了变化,如图所示

前端全栈框架 -  Express 安装与使用  - 《手把手带你从零开始学全栈》

happy 的值设为 true 时,如图所示

前端全栈框架 -  Express 安装与使用  - 《手把手带你从零开始学全栈》

在页面开发过程中,除了条件渲染,循环渲染也是一种常用的方式,最常见的就是渲染一个列表;在art-template中,循环渲染也特别简单

5-5. 基本循环渲染

首先在路由中定义一个数组,数组中的每一项都是一个对象,需要将数组渲染到页面上,每一条数据对应数组中的一项;定义路由的代码如下:

// 定义一个GET请求“/”的路由
router.get('/', function(req, res, next) {
  // 渲染index页面,传入渲染对象
  res.render('index', {
    title: 'Hello',
    // 定义一个数组,每一项都是一个对象
    list: [{
      id: 1,
      content: '今天天气不错'
    }, {
      id: 2,
      content: '昨天你吃了什么?'
    }, {
      id: 3,
      content: '工作好累'
    }]
  });
});

修改页面文件代码:

<! DOCTYPE html>
  <html lang="en">

  <head>
    <meta charset="UTF-8">
    <title>Title</title>
  </head>

  <body>
    <h2>{{title}}</h2>
    <! -- 循环list,每一项为item -->
      {{each list as item }}
      <p>数据id:{{item.id}},内容:{{item.content}}</p>
      {{/each}}
  </body>

  </html>

在浏览器中查看,效果图如下

前端全栈框架 -  Express 安装与使用  - 《手把手带你从零开始学全栈》

特别简单是不是?跟条件渲染一样,在 art-template 中循环渲染也有固定的写法:

{{each LIST as ITEM}} (LIST为数组字段,ITEM为数组中的每一项) 开头

{{/each}}结尾,需要循环的内容放在其中

5-6. 循环渲染结合条件渲染

在实际的业务场景中,通常不会简单地渲染列表,而往往需要在循环过程中进行一些判断,根据判断的结果展示不同的页面,也就是在循环渲染中增加条件渲染

下面结合上一节的条件渲染给大家展示一个综合的例子;定义路由代码:

// 定义一个GET请求“/”的路由
router.get('/', function (req, res, next) {
  // 渲染index页面,传入渲染对象
  res.render('index', {
    title: 'Hello',
    // 定义一个数组,每一项都是一个对象
    list: [{
      id: 1,
      content: '今天天气不错'
    }, {
      id: 2,
      content: '昨天你吃了什么?'
    }, {
      id: 3,
      content: '工作好累'
    }],
    // 定义一个变量,表示当前被选中的id
    targetId: 2
  });
});

修改页面文件代码:

<! DOCTYPE html>
  <html lang="en">

  <head>
    <meta charset="UTF-8">
    <title>Title</title>
  </head>

  <body>
    <h2>{{title}}</h2>
    <! -- 循环list,每一项为item -->
      {{each list as item }}
      <! -- 判断list中的每一项item的id属性是否等于targetId字段 -->
        {{if item.id === targetId}}
        <p style="color: #f00; ">数据id:{{item.id}},内容:{{item.content}}</p>
        {{else}}
        <p>数据id:{{item.id}},内容:{{item.content}}</p>
        {{/if}}
        {{/each}}
  </body>

  </html>

来看看效果

前端全栈框架 -  Express 安装与使用  - 《手把手带你从零开始学全栈》

在这个示例中,对 list 这个数组字段进行了循环渲染,同时在循环中又进行了判断,只有当 list 中某一条数据的 id 值等于 targetId 这个字段值的时候,才将这一条数据展示为红色