Nodejs内容

博客笔记:01 【nodejs简介】 | dselegent-blog

项目:笔记本

开发过程:

基本结构搭建

1、express -e accounts

2、修改package.json 将node修改成nodemon(可以自动重启)

3、app.js中修改路由 在indexRouter路由界面中添加

// routes\index.js
var express = require('express');
var router = express.Router();

/* 记账本列表 */
router.get('/account', function(req, res, next) {
  res.send('账本列表')
});

// 添加记录
router.get('/account/create',function(req, res, next) {
  res.send('添加记录')
});

module.exports = router;

相应静态网页

app.js中渲染出index.html页面

/* 记账本列表 */
router.get('/account', function(req, res, next) {
  // 渲染模板
  res.render('list')
});

添加list页面

// views\list.ejs
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Document</title>
    <link
      href="https://cdn.bootcdn.net/ajax/libs/twitter-bootstrap/3.3.7/css/bootstrap.css"
      rel="stylesheet"
    />
    <style>
      label &#123;
        font-weight: normal;
      &#125;
      .panel-body .glyphicon-remove&#123;
        display: none;
      &#125;
      .panel-body:hover .glyphicon-remove&#123;
        display: inline-block
      &#125;
    </style>
  </head>
  <body>
    <div class="container">
      <div class="row">
        <div class="col-xs-12 col-lg-8 col-lg-offset-2">
          <h2>记账本</h2>
          <hr />
          <div class="accounts">
            <div class="panel panel-danger">
              <div class="panel-heading">2023-04-05</div>
              <div class="panel-body">
                <div class="col-xs-6">抽烟只抽煊赫门,一生只爱一个人</div>
                <div class="col-xs-2 text-center">
                  <span class="label label-warning">支出</span>
                </div>
                <div class="col-xs-2 text-right">25 元</div>
                <div class="col-xs-2 text-right">
                  <span
                    class="glyphicon glyphicon-remove"
                    aria-hidden="true"
                  ></span>
                </div>
              </div>
            </div>
            <div class="panel panel-success">
              <div class="panel-heading">2023-04-15</div>
              <div class="panel-body">
                <div class="col-xs-6">3 月份发工资</div>
                <div class="col-xs-2 text-center">
                  <span class="label label-success">收入</span>
                </div>
                <div class="col-xs-2 text-right">4396 元</div>
                <div class="col-xs-2 text-right">
                  <span
                    class="glyphicon glyphicon-remove"
                    aria-hidden="true"
                  ></span>
                </div>
              </div>
            </div>
          </div>
        </div>
      </div>
    </div>
  </body>
</html>

同样添加记录页面也这样渲染出来

ps:在添加记录页面时bug:css和js文件放置在public文件夹下,但是通过相对路径引入时会收到页面url的影响,路径变化会导致相对路径变化,导致它不确定,所有改成绝对路径,它会与域名进行一个拼接。

获取表单数据

在create.js中的表单项中添加name属性,form上添加action属性’/account’ 和method属性 post

同时在index.js中添加新增记录的跳转

// 新增记录
router.post('/account',(req,res) => &#123;
  // 获取请求体数据
  // 这里打印出来是在控制台下打印 而不是在浏览器中打印
  console.log(req.body);
  res.send('新增记录')
&#125;)

lowdb介绍与使用

lowdb存储数据

npm官网:

lowdb - npm (npmjs.com)

主要安装的是lowdb@1.0.0版本

对数据的操作

// test\lowdb.js
// 导入lowdb
const low = require('lowdb')
const FileSync = require('lowdb/adapters/FileSync')
const adapter = new FileSync('db.json')
// 获取db对象
const db = low(adapter)

// 初始化数据
// db.defaults(&#123; posts: [], user:&#123;&#125; &#125;).write()

// 写入数据
// db.get('posts').push(&#123;id:1,title:'nice'&#125;).write()
// db.get('posts').push(&#123;id:2,title:'trip'&#125;).write()

// 获取数据
// console.log(db.get('posts').value())

// 删除数据
// let res = db.get('posts').remove(&#123;id: 1&#125;).write()
// console.log(res);

// 更新数据
let res = db.get('posts').find(&#123;id: 2&#125;)
res.assign(&#123;title: 'nihao!!'&#125;).write()

执行代码:控制台输入

PS D:\accounts\test> node lowdb.js

保存账单信息

使用lowdb版本

// routes\index.js
// 导入lowdb
const low = require('lowdb')
const FileSync = require('lowdb/adapters/FileSync')
// 这里一定要注意生成的db数据的位置 否则容易报错
const adapter = new FileSync(__dirname + '/../data/db.json')

// 获取db对象
const db = low(adapter)
// 新增记录
router.post('/account',(req,res) => &#123;
  // 获取请求体数据
  // 这里打印出来是在控制台下打印 而不是在浏览器中打印
  // console.log(req.body);
  // 生成id
  let id = shortId.generate()
  res.send('新增记录')
  // 将获取到的记录写入到db.json中
  db.get('accounts').unshift(&#123;id:id,...req.body&#125;).write();
&#125;)

ps: 这里使用了shortid来表示每条账单的id,需要安装第三方库

npm i shortid

完善成功提醒

添加success页面,成功了之后渲染

添加跳转到首页的连接

// views\success.ejs
<body>
  <div class="container">
    <div class="h-50"></div>
    <div class="alert alert-success" role="alert">
      <h1>:) <%= msg %></h1>
      <p> <a href="<%= url %>">点击跳转</a></p>
    </div>
  </div>
</body>
// routes\index.js
// 生成提示
  res.render('success',&#123;msg: '添加成功哦!!', url: '/account'&#125;)

账单列表

获取到accounts数据之后主要在页面上进行显示 那么需要在模板上进行forEach展示

// views\list.ejs
// 注意这里 <% %>的使用
<div class="accounts">
<% accounts.forEach(item => &#123; %>
<div class="panel <%= item.type === '-1' ? 'panel-danger' : 'panel-success' %>">
  <div class="panel-heading"><%= item.time%></div>
  <div class="panel-body">
    <div class="col-xs-6"><%= item.title%></div>
    <div class="col-xs-2 text-center">
      <span class="label <%= item.type === '-1' ? 'label-warning' : 'label-success' %>"> <%= item.type === '-1' ? '支出' : '收入' %></span>
    </div>
    <div class="col-xs-2 text-right"><%= item.account%>元</div>
    <div class="col-xs-2 text-right">
      <span
        class="glyphicon glyphicon-remove"
        aria-hidden="true"
      ></span>
    </div>
  </div>
</div>
<% &#125;) %>
</div>

删除账单

添加删除路由

// routes\index.js
// 删除记录
// 使用params的参数写法
router.get('/account/:id',(req,res)=> &#123;
  let id = req.params.id;
  db.get('accounts').remove(&#123;id:id&#125;).write()
  res.render('success',&#123;msg: '删除成功哦!!', url: '/account'&#125;)
&#125;)

在模板上的x添加跳转按钮 即点击就跳转到删除路由中

// views\list.ejs
// 给span标签包裹上一个a标签即可
<a href="/account/<%=item.id%>">
    <span
      class="glyphicon glyphicon-remove"
      aria-hidden="true"
    >
    </span>
</a>

结合数据库

使用mongoose连接mongodb数据库

// connectMongodb.js 只是练习使用与正式项目中的连接有差别
// 1、安装mongoose
// npm i mongoose
// 2、导入
const mongoose = require('mongoose');

// 3、连接mongodb服务
mongoose.connect('mongodb://127.0.0.1:27017/admin');

// 4、设置回调 不用on 推荐用once 只执行一次
mongoose.connection.once('open',()=>&#123;
  console.log('连接成功');
&#125;)

mongoose.connection.on('error',()=>&#123;
  console.log('连接失败');
&#125;)

mongoose.connection.on('close',()=>&#123;
  console.log('连接关闭');
&#125;)

运行时:node connectMongodb.js

拿进数据库的基本操作

在入口文件中连接数据库

// bin\www
// 导入db函数
const db = require('../db/db.js');
// 调用db函数 将原来所有的内容包裹在下方回调函数中
// 含义为:连接上了数据库才能进行项目的运行
db(()=>{ })

创建模型文件

// models\AccountModel.js
//导入 mongoose
const mongoose = require('mongoose');
//创建文档的结构对象
//设置集合中文档的属性以及属性值的类型
let AccountSchema = new mongoose.Schema(&#123;
  //标题
  title: &#123;
    type: String,
    required: true
  &#125;,
  //时间
  time: Date,
  //类型
  type: &#123;
    type: Number,
    default: -1
  &#125;,
  //金额
  account: &#123;
    type: Number,
    required: true
  &#125;,
  //备注
  remarks: &#123;
    type: String 
  &#125;
&#125;);

插入数据库

// routes\index.js
// 使用moment将string类型转换成Date类型
const moment = require('moment');
const AccountModel = require('../models/AccountModel')
// 现在要使用promise的写法
const result = AccountModel.create({
    ...req.body,
    time: moment(req.body.time).toDate()
});
result.then((err) {
    res.status(500).send('插入失败')
    return;
})

读取数据库

// routes\index.js
// 通过数据库获取到数据
const accounts = AccountModel.find().sort(&#123;time: -1&#125;)
accounts.then((data) => &#123;
// 渲染模板 且传递参数
res.render('list',&#123;accounts: data, moment: moment&#125;)
&#125;)
// views\list.ejs 
// 对日期做格式化
<div class="panel-heading"><%= moment(item.time).format('YYYY-MM-DD') %></div>

删除数据库

const result = AccountModel.deleteOne({id: id})
  result.then((data) => {
    console.log(data);
  })

结合API

新建routes\account.js 主要用于api访问,然后在app.js中引入

const accountRouter = require('./routes/account.js')
// 使得页面通过api接口可以访问
app.use('/api', accountRouter)

获取账单接口