Express+EJS实现一个新闻列表页面的新增和查看

1、模块化思路

服务模块:负责启动服务

路由模块:负责路由判断

业务模块:负责处理具体路由的业务代码

数据操作模块:负责进行数据库操作

配置模块:负责各个模块中用到的配置信息

2、项目目录

新建项目文件夹,安装express和EJS

3、配置模块

config.js

// 配置模块:
const path = require('path');

module.exports = {
  port: 8080,
  dataPath: path.join(__dirname, 'data', 'data.json'),
  viewPath: path.join(__dirname, 'views')
};

4、方法模块:封装一些重复利用的方法

method.js

// 封装一些方法
const fs = require('fs');
const path = require('path');
const querystring = require('querystring');
const config = require('./config.js');

// 封装读取data.json文件的方法
module.exports.readData = function (callback) {
  fs.readFile(config.dataPath, 'utf8', (err, data) => {
    if (err && err.code !== 'ENOENT') throw err;
    // 将读取到的字符串数据转换成JSON对象
    var list = JSON.parse(data || '[]');
    // 通过调用回调函数,将读取到的数据list传递出去
    callback(list);
  })
}

// 封装写入data.json文件的方法
module.exports.writeData = function (data, callback) {
  fs.writeFile(config.dataPath, data, err => {
    if(err) throw err;
    callback();
  })
}

// 封装获取用户post提交的数据的方法
module.exports.getPostData = function (req, callback) {
  // 声明一个数组,用来保存用户每次提交过来的数据
  var array = [];
  req.on('data', chunk => {
    // 此处的chunk参数,就是浏览器本次提交过来的一部分数据
    // chunk 的数据类型是Buffer (chunk就是一个Buffer对象)
    array.push(chunk);
  });
  req.on('end', function () {
    // 把 array 中的所有数据汇总起来,然后把array中的Buffer对象集合起来,转换成一个Buffer对象
    // Buffer.concat方法将一组Buffer对象合并为一个Buffer对象。
    var postData = Buffer.concat(array);
    // 将获得的Buffer对象转换成一个字符串
    postData = postData.toString('utf8');
    // 将post请求的查询字符串,转换成一个JSON对象,用到node.js中的 querystring 模块
    postData = querystring.parse(postData);
    callback(postData);
  });
}

5、业务模块

handler.js

// 业务模块
const method = require('./method.js');
const path = require('path');
const config = require('./config.js');

module.exports.index = function (req, res) {
  method.readData(list => {
    // res.render()方法,默认是不能使用的,需要为express配置一个模板引擎,才能使用res.render()
    // 在app.js中设置了HTML模板所在路径和要使用的模板引擎,在这里就可以直接使用res.render()了
    // 第一个参数:HTML模板文件名,第二个参数:要传入HTML模板文件的数据,第三个参数:回调函数
    res.render('index', {list: list}, (err, html) => {
      if(err) throw err;
      console.log('ok');
      res.send(html);
    });
  });
};

module.exports.submit = function (req, res) {
  res.sendFile(path.join(config.viewPath, 'submit.html'), err => {
    if(err) throw err;
    console.log('ok');
  });
};

module.exports.detail = function (req, res) {
  // 1、获取当前用户请求的新闻的id
  console.log(req.query.id);
  // 2、读取data.json文件中的数据,根据id找到对应的新闻数据
  method.readData(list => {
    var model = null;
    for(var i = 0; i < list.length; i++) {
      if(list[i].id.toString() === req.query.id) {
        model = list[i];
        break;
      }
    }
    if(model) {
      // 3、调用res.render()函数进行模板引擎的渲染
      res.render('detail', {item: model},  (err, html) => {
        if(err) throw err;
        console.log('ok detail');
        res.send(html);
      });
    } else {
      res.status(404).send('404, Not Found! 页面不存在');
    }
  });
};

module.exports.getAdd = function (req, res) {
  method.readData(list => {
    // 保存新闻数据时增加一个id属性
    req.query.id = list.length;
    list.push(req.query);
    method.writeData(JSON.stringify(list), function () {
      console.log('ok');
      res.redirect('/');
    });
  });
};

module.exports.postAdd = function (req, res) {
  method.readData(list => {
    method.getPostData(req, postData => {
      // 保存新闻数据时增加一个id属性
      postData.id = list.length;
      list.push(postData);
      method.writeData(JSON.stringify(list), function () {
        console.log('post ok');
        // 重定向到新闻列表页面
        res.redirect('/');
      });
    });
  });
};

6、路由模块

router.js

// 路由模块:负责路由判断

// 1、创建一个路由对象 router (router即是一个对象,也是一个函数)
const express = require('express');
const path = require('path');
const router = express.Router();

// 加载业务模块
const handler = require('./handler.js');

// 2、把所有路由都挂载到router上
// router.get('/', (req, res) => {
//   handler.index(req, res);
// });
// 等价于
router.get('/', handler.index);
router.get('/index', handler.index);
router.get('/submit', handler.submit);
router.get('/detail', handler.detail);
router.get('/add', handler.getAdd);
router.post('/add', handler.postAdd);
// 对resources文件夹下的内容进行静态资源托管
router.use('/resources', express.static(path.join(__dirname, 'resources')));

// 3、返回router对象
module.exports = router;

7、服务模块

app.js

// 入口文件
// 服务模块:负责启动服务

// 1、加载express模块
const express = require('express');
// 2、创建app对象
const app = express();
const ejs = require('ejs');
const path =require('path');

// 加载配置模块
const config = require('./config.js');
// 加载路由模块
const router = require('./router.js');

// 模板所在路径
app.set('views', config.viewPath);
// 设置要用的模板引擎
app.set('view engine', 'ejs');
// 3、注册路由
// 设置app与router相关联
// app.use第一个参数不传,默认为'/'
app.use(router);



// 4、启动服务
app.listen(config.port, () => {
  console.log(`http://localhost:${config.port}`);
});

8、三个HTML页面代码

index.ejs

  <ul>
    <% for(var i = 0; i < list.length; i++) { %>
      <li>
        <span><%= list[i].id+1 %>.</span>
        <a href="/detail?id=<%= list[i].id %>"><%= list[i].title %></a>
      </li>
    <% } %>
  </ul>

detail.ejs

  <h1><%= item.title %></h1>
  <p><%= item.text %></p>

submit.html

  <form method="post" action="/add">
    <table>
      <tr>
        <td>title:</td>
        <td><input type="text" name="title" value="" size="50"/></td>
      </tr>
      <tr>
        <td>text:</td>
        <td><textarea name="text" id="" cols="50" rows="4"></textarea></td>
      </tr>
      <tr>
        <td><input type="submit" value="提交"></td>
        <td><input type="reset" value="重置"></td>
      </tr>     
    </table>
  </form>

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
以下是一个基于 NodejsExpressEJS 的分页查询实现示例: 首先,安装必要的依赖: ``` npm install express ejs mongoose express-flash express-session ``` 然后,创建一个名为 `app.js` 的文件,引入所需模块: ```javascript const express = require('express'); const mongoose = require('mongoose'); const session = require('express-session'); const flash = require('express-flash'); const bodyParser = require('body-parser'); const app = express(); const port = process.env.PORT || 3000; // 连接 MongoDB 数据库 mongoose.connect('mongodb://localhost:27017/test', {useNewUrlParser: true, useUnifiedTopology: true}); // 定义数据库模型 const Article = mongoose.model('Article', { title: String, content: String, created_at: Date }); // 设置模板引擎和静态文件目录 app.set('view engine', 'ejs'); app.use(express.static(__dirname + '/public')); // 设置 session 和 flash app.use(session({ secret: 'mysecretkey', resave: true, saveUninitialized: true })); app.use(flash()); // 设置 bodyParser app.use(bodyParser.urlencoded({ extended: true })); // 定义路由 app.get('/', async function(req, res) { const perPage = 5; const page = req.query.page || 1; const articles = await Article.find() .skip((perPage * page) - perPage) .limit(perPage); const count = await Article.countDocuments(); const totalPages = Math.ceil(count / perPage); res.render('index', { articles: articles, current: page, pages: totalPages }); }); app.listen(port, function() { console.log('Server listening on port ' + port); }); ``` 在 `views` 文件夹中创建一个名为 `index.ejs` 的文件,用于显示分页数据: ```html <!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title>分页查询</title> </head> <body> <h1>文章列表</h1> <% if (articles.length > 0) { %> <ul> <% articles.forEach(function(article) { %> <li><%= article.title %></li> <% }); %> </ul> <% } else { %> <p>没有文章。</p> <% } %> <% if (pages > 1) { %> <div class="pagination"> <ul> <% if (current == 1) { %> <li class="disabled"><span>«</span></li> <% } else { %> <li><a href="?page=<%= current - 1 %>">«</a></li> <% } %> <% for (var i = 1; i <= pages; i++) { %> <% if (i == current) { %> <li class="active"><span><%= i %></span></li> <% } else { %> <li><a href="?page=<%= i %>"><%= i %></a></li> <% } %> <% } %> <% if (current == pages) { %> <li class="disabled"><span>»</span></li> <% } else { %> <li><a href="?page=<%= current + 1 %>">»</a></li> <% } %> </ul> </div> <% } %> </body> </html> ``` 在上面的示例中,我们使用了 `mongoose` 连接 MongoDB 数据库,并定义了一个名为 `Article` 的数据库模型。在路由中,我们使用 `await` 关键字来等待查询结果,并通过 `skip()` 和 `limit()` 方法来实现分页查询。在视图中,我们使用 EJS 模板引擎来生成分页链接。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值