webpack4+express+mongodb+vue实现增删改查的示例


Posted in Javascript onNovember 08, 2018

在讲解之前,我们先来看看效果如下所示:

1)整个页面的效果如下:

webpack4+express+mongodb+vue实现增删改查的示例

2) 新增数据效果如下:

webpack4+express+mongodb+vue实现增删改查的示例

3) 新增成功如下:

webpack4+express+mongodb+vue实现增删改查的示例

4) 编辑数据效果如下:

webpack4+express+mongodb+vue实现增删改查的示例

5) 编辑成功效果如下:

webpack4+express+mongodb+vue实现增删改查的示例

6) 删除数据效果如下:

webpack4+express+mongodb+vue实现增删改查的示例

7) 删除成功效果如下:

webpack4+express+mongodb+vue实现增删改查的示例

8) 查询效果如下:

webpack4+express+mongodb+vue实现增删改查的示例

如上的效果,下面我们还是和之前一样,先看看我们整个项目的架构如下所示:

### 目录结构如下:
demo1          # 工程名
| |--- dist        # 打包后生成的目录文件    
| |--- node_modules      # 所有的依赖包
| |----database       # 数据库相关的文件目录
| | |---db.js        # mongoose类库的数据库连接操作
| | |---user.js       # Schema 创建模型
| | |---addAndDelete.js     # 增删改查操作
| |--- app
| | |---index
| | | |-- views       # 存放所有vue页面文件
| | | | |-- list.vue      # 列表数据
| | | | |-- index.vue
| | | |-- components      # 存放vue公用的组件
| | | |-- js        # 存放js文件的
| | | |-- css        # 存放css文件
| | | |-- store       # store仓库
| | | | |--- actions.js
| | | | |--- mutations.js
| | | | |--- state.js
| | | | |--- mutations-types.js
| | | | |--- index.js
| | | | |
| | | |-- app.js       # vue入口配置文件
| | | |-- router.js      # 路由配置文件
| |--- views
| | |-- index.html      # html文件
| |--- webpack.config.js     # webpack配置文件 
| |--- .gitignore 
| |--- README.md
| |--- package.json
| |--- .babelrc       # babel转码文件
| |--- app.js        # express入口文件

如上目录架构是我现在整个项目的架构图,其中database目录下存放 db.js ,该文件最主要是使用 mongoose 数据库连接操作,user.js 文件是创建一个Schema模型,也可以理解为表结构,addAndDelete.js 文件内部实现增删改查操作。

先在本地把数据库搭建起来后,再慢慢学习哦,我这边文章实现 vue+mongodb 实现增删改查也是基于上面这些文章的基础之上来进行的,特别是居于这篇 使用Mongoose类库实现简单的增删改查

( https://3water.com/article/150381.htm) 来进行的,增删改查操作及使用Schema 创建模型 都是居于这篇文章的基础之上再进行使用vue来重构下的。本篇文章也是依赖于饿了么vue组件进行开发的。

先来分别讲下代码结构吧:

1)使用express创建服务器

首先我们在项目的根目录新建app.js, 该app.js 主要实现的功能是 启动 3001端口的服务器,并且使用 bodyParser进行解析数据,如下代码:

// 引入express模块
const express = require('express');

// 创建app对象
const app = express();

const addAndDelete = require('./database/addAndDelete');

const bodyParser = require("body-parser")

app.use(bodyParser.json());

app.use(bodyParser.urlencoded({ extended: false }));

// 使用
app.use('/api', addAndDelete);

// 定义服务器启动端口 
app.listen(3001, () => {
 console.log('app listening on port 3001');
});

进入我们项目的根目录后,运行 node app.js 即可创建一个 http://127.0.0.1:3001 的服务器页面了。

2)数据库连接

在database/db.js 链接 mongodb://localhost:27017/dataDb 数据库。使用mongoose类库,如果不理解mongoose类库的话,可以返回来看我这篇文章(https://3water.com/article/150381.htm)如下代码:

var mongoose = require('mongoose');
var DB_URL = 'mongodb://localhost:27017/dataDb';

/* 链接 */
mongoose.connect(DB_URL);

/* 链接成功 */
mongoose.connection.on('connected', function() {
 console.log('Mongoose connection open to ' + DB_URL);
});

// 链接异常
mongoose.connection.on('error', function(err) {
 console.log('Mongoose connection error:' + err);
});

// 链接断开

mongoose.connection.on('disconnected', function() {
 console.log('Mongoose connection disconnected');
});
module.exports = mongoose;

3)创建数据模型

在database/user.js 中使用 Schema创建一个模型,也就是说上面的 dataDb是数据库名称,这边使用schema创建的模型就是表结构的字段,有如下 name, age, sex 三个字段,代码如下所示:

/*
 定义一个user的Schema
*/
const mongoose = require('./db.js');
const Schema = mongoose.Schema;

// 创建一个模型
const UserSchema = new Schema({
 name: { type: String }, // 属性name,类型为String
 age: { type: Number, default: 30 }, // 属性age,类型为Number,默认值为30
 sex: { type: String }
});

// 导出model模块
const User = module.exports = mongoose.model('User', UserSchema);

4)实现增删改查路由接口

如下所有的增删改查的代码如下(如果代码看不懂的话,还是返回看这篇文章即可: https://3water.com/article/150381.htm):

// 引入express 模块 
const express = require('express');

const router = express.Router();

// 引入user.js
const User = require('./user');

// 新增一条数据 接口为add
router.post('/add', (req, res) => {
 const user = new User({
 name: req.body.name,
 age: req.body.age,
 sex: req.body.sex
 });
 user.save((err, docs) => {
 if (err) {
  res.send({ 'code': 1, 'errorMsg': '新增失败' });
 } else {
  res.send({ "code": 0, 'message': '新增成功' });
 }
 });
});

// 查询数据 
router.post('/query', (req, res) => {
 const name = req.body.name,
 age = req.body.age,
 sex = req.body.sex;
 const obj = {};
 if (name !== '') {
 obj['name'] = name;
 }
 if (age !== '') {
 obj['age'] = age;
 }
 if (sex !== '') {
 obj['sex'] = sex;
 }
 User.find(obj, (err, docs) => {
 if (err) {
  res.send({ 'code': 1, 'errorMsg': '查询失败' });
 } else {
  res.send(docs);
 }
 });
});

// 根据 _id 删除数据
router.post('/del', (req, res) => {
 const id = req.body.id;
 // 根据自动分配的 _id 进行删除
 const whereid = { '_id': id };
 User.remove(whereid, (err, docs) => {
 if (err) {
  res.send({ 'code': 1, 'errorMsg': '删除失败' });
 } else {
  res.send(docs);
 }
 })
});

// 更新数据
router.post('/update', (req, res) => {
 console.log(req.body)
 // 需要更新的数据
 const id = req.body.id,
 name = req.body.name,
 age = req.body.age,
 sex = req.body.sex;
 const updateStr = {
 name: name,
 age: age,
 sex: sex
 };
 const ids = {
 _id: id
 };
 console.log(ids);
 User.findByIdAndUpdate(ids, updateStr, (err, docs) => {
 if (err) {
  res.send({ 'code': 1, 'errorMsg': '更新失败' });
 } else {
  res.send(docs);
 }
 });
});
module.exports = router;

5)搭建vue页面,如何通过页面的接口请求?

在app/index/views/list.vue 基本代码如下(所有的html代码是基于饿了么vue组件的,最主要一些form表单组件的用法及表格的插件及弹窗的插件),代码如下:

<style lang="stylus">
 #list-container 
 width 100%
</style>
<template>
 <div id="list-container" style="margin:20px auto">
 <div style="width:100%;overflow:hidden;">
  <el-form ref="form" label-width="80px">
  <div style="float:left;width:20%">
   <el-form-item label="姓名">
   <el-input v-model="name"></el-input>
   </el-form-item>
  </div>
  <div style="float:left;width:20%">
   <el-form-item label="年龄">
   <el-input v-model="age"></el-input>
   </el-form-item>
  </div>
  <div style="float:left;width:20%">
   <el-form-item label="性别">
   <el-select v-model="sex">
    <el-option
    v-for="item in options2"
    :key="item.value"
    :label="item.label"
    :value="item.value">
    </el-option>
   </el-select>
   </el-form-item>
  </div>
  <el-button type="primary" style="margin-left:20px;" @click="query(true)">查 询</el-button>
  <el-button type="success" @click="newAdd">新 增</el-button>
  </el-form>
 </div>
 <div style="width:90%; margin: 0 auto; border: 1px solid #ebebeb; border-radius: 3px;overflow:hidden;">
  <el-table
  :data="tableData"
  style="width: 100%">
  <el-table-column
   prop="name"
   label="姓名"
   width="180">
  </el-table-column>
  <el-table-column
   prop="age"
   label="年龄"
   width="180">
  </el-table-column>
  <el-table-column
   prop="sex"
   label="性别">
  </el-table-column>
  <el-table-column
   fixed="right"
   label="操作"
   width="100">
   <template slot-scope="scope">
   <el-button type="text" size="small" @click="editFunc(scope.row)">编辑</el-button>
   <el-button type="text" size="small" @click="delFunc(scope.row)">删除</el-button>
   </template>
  </el-table-column>
  </el-table>
 </div>
 <el-dialog
  title="新增"
  :visible.sync="dialogVisible"
  width="30%">
  <el-form label-width="40px">
  <div style="float:left;width:100%">
   <el-form-item label="姓名">
   <el-input v-model="add.name"></el-input>
   </el-form-item>
  </div>
  <div style="float:left;width:100%">
   <el-form-item label="年龄">
   <el-input v-model="add.age"></el-input>
   </el-form-item>
  </div>
  <div style="float:left;width:100%">
   <el-form-item label="性别">
   <el-select v-model="add.sex">
    <el-option
    v-for="item in options2"
    :key="item.value"
    :label="item.label"
    :value="item.value">
    </el-option>
   </el-select>
   </el-form-item>
  </div>
  </el-form>
  <span slot="footer" class="dialog-footer">
  <el-button @click="dialogVisible = false">取 消</el-button>
  <el-button type="primary" @click="addConfirm">确 定</el-button>
  </span>
 </el-dialog>
 <el-dialog
  title="编辑"
  :visible.sync="dialogVisible2"
  width="30%">
  <el-form label-width="40px">
  <div style="float:left;width:100%">
   <el-form-item label="姓名">
   <el-input v-model="update.name"></el-input>
   </el-form-item>
  </div>
  <div style="float:left;width:100%">
   <el-form-item label="年龄">
   <el-input v-model="update.age"></el-input>
   </el-form-item>
  </div>
  <div style="float:left;width:100%">
   <el-form-item label="性别">
   <el-select v-model="update.sex">
    <el-option
    v-for="item in options2"
    :key="item.value"
    :label="item.label"
    :value="item.value">
    </el-option>
   </el-select>
   </el-form-item>
  </div>
  </el-form>
  <span slot="footer" class="dialog-footer">
  <el-button @click="dialogVisible = false">取 消</el-button>
  <el-button type="primary" @click="editConfirm">确 定</el-button>
  </span>
 </el-dialog>
 <el-dialog
  title="提示"
  :visible.sync="dialogVisible3"
  width="30%">
  <div>是否确认删除?</div>
  <span slot="footer" class="dialog-footer">
  <el-button @click="dialogVisible3 = false">取 消</el-button>
  <el-button type="primary" @click="delConfirm">确 定</el-button>
  </span>
 </el-dialog>
 </div>
</template>

<script type="text/javascript">
 export default {
 data() {
  return { 
  formLabelWidth: '120px',
  name: '',
  age: '',
  sex: '',
  options2: [
   {
   value: '1',
   label: '男'
   }, {
   value: '2',
   label: '女'
   }
  ],
  tableData: [],
  // 新增页面
  add: {
   name: '',
   age: '',
   sex: ''
  },
  // 修改页面
  update: {
   name: '',
   age: '',
   sex: ''
  },
  dialogVisible: false,
  dialogVisible2: false,
  dialogVisible3: false,
  row: null,
  _id: ''
  }
 },
 created() {
  this.query();
 },
 methods: {
  setData(datas) {
  if (datas.length > 0) {
   for (let i = 0; i < datas.length; i++) {
   if (datas[i].sex * 1 === 1) {
    this.$set(datas[i], 'sex', '男');
   } else if (datas[i].sex * 1 === 2) {
    this.$set(datas[i], 'sex', '女');
   }
   }
  }
  return datas;
  },
  // 查询数据
  query(isquery) {
  const obj = {
   name: this.name,
   age: this.age,
   sex: this.sex
  };
  this.$http.post('/api/query', obj).then((res) => {
   if (res.ok) {
   this.tableData = res.body ? this.setData(res.body) : [];
   if (isquery) {
    this.$message({
    message: '查询成功',
    type: 'success'
    });
   }
   } else {
   if (isquery) {
    this.$message({
    message: '查询失败',
    type: 'warning'
    });
   }
   this.tableData = [];
   }
  });
  },
  newAdd() {
  this.dialogVisible = true;
  },
  editFunc(row) {
  this.dialogVisible2 = true;
  this._id = row._id;
  this.$set(this.$data.update, 'name', row.name);
  this.$set(this.$data.update, 'age', row.age);
  this.$set(this.$data.update, 'sex', row.sex);
  this.row = row;
  },
  delFunc(row) {
  this.dialogVisible3 = true;
  console.log(row);
  this.row = row;
  },
  // 编辑页面提交
  editConfirm() {
  const id = this._id,
   name = this.update.name,
   age = this.update.age,
   sex = this.update.sex;
  const obj = {
   id: id,
   name: name,
   age: age,
   sex: sex
  };
  this.$http.post('/api/update', obj).then((res) => {
   if (res.ok) {
   // 删除成功
   this.$message({
    message: '更新成功',
    type: 'success'
   });
   // 重新请求下查询
   this.query(false);
   } else {
   // 删除成功
   this.$message({
    message: '更新失败',
    type: 'success'
   });
   }
   this.dialogVisible2 = false;
  });
  },
  // 删除提交
  delConfirm() {
  const obj = {
   'id': this.row._id
  };
  this.$http.post('/api/del', obj).then((res) => {
   console.log(res.body)
   if (res.body.ok) {
   // 删除成功
   this.$message({
    message: '删除成功',
    type: 'success'
   });
   // 成功后,触发重新查询下数据 
   this.query();
   } else {
   // 删除失败
   this.$message({
    message: res.body.errorMsg,
    type: 'warning'
   });
   }
   this.dialogVisible3 = false;
  });
  },
  // 新增提交
  addConfirm() {
  // 新增的时候,姓名,年龄,性别 不能为空,这里就不判断了。。。
  const obj = {
   name: this.add.name,
   age: this.add.age,
   sex: this.add.sex
  };
  this.$http.post('/api/add', obj).then((res) => {
   console.log(111);
   console.log(res);
   if (res.body.code === 0) {
   this.$message({
    message: '新增成功',
    type: 'success'
   });
   // 成功后,触发重新查询下数据 
   this.query();
   } else {
   this.$message({
    message: res.body.errorMsg,
    type: 'warning'
   });
   }
   this.dialogVisible = false;
  });
  }
 }
 }
</script>

6. 解决跨域问题,及接口如何访问的?

首先我们是使用express启动的是 http://127.0.0.1:3001 服务器的,但是在我们的webpack中使用的是8081端口的,也就是说页面访问的是http://127.0.0.1:8081/ 这样访问的话,因此肯定会存在接口跨域问题的,因此我们需要在webpack中使用 devServer.proxy 配置项配置一下,如下代码配置:

module.exports = {
 devServer: {
 port: 8081,
 // host: '0.0.0.0',
 headers: {
  'X-foo': '112233'
 },
 inline: true,
 overlay: true,
 stats: 'errors-only',
 proxy: {
  '/api': {
  target: 'http://127.0.0.1:3001',
  changeOrigin: true // 是否跨域
  }
 }
 },
}

因为我list.vue页面所有的请求都是类似于这样请求的 this.$http.post('/api/query', obj); 因此当我使用 /api/query请求的话,它会被代理到 http://127.0.0.1:3001/api/query, 这样就可以解决跨域的问题了,同时我们在项目的根目录中的 将路由应用到 app.js 中,有如下这句代码:

const addAndDelete = require('./database/addAndDelete');
app.use('/api', addAndDelete);

当请求http://127.0.0.1:3001/api/query的时候,会自动使用 addAndDelete.js 中的 /query的接口方法。

查看github代码

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

Javascript 相关文章推荐
ajax处理php返回json数据的实例代码
Jan 24 Javascript
jQuery实现动画效果的简单实例
Jan 27 Javascript
js截取中英文字符串、标点符号无乱码示例解读
Apr 17 Javascript
浅谈toLowerCase和toLocaleLowerCase的区别
Aug 15 Javascript
JS 实现 ajax 异步浏览器兼容问题
Jan 21 Javascript
Javascript封装id、class与元素选择器方法示例
Mar 13 Javascript
利用C/C++编写node.js原生模块的方法教程
Jul 07 Javascript
Angular使用操作事件指令ng-click传多个参数示例
Mar 27 Javascript
Koa项目搭建过程详细记录
Apr 12 Javascript
vue实现学生录入系统之添加删除功能
Jul 11 Javascript
vue.js 输入框输入值自动过滤特殊字符替换中问标点操作
Aug 31 Javascript
详解React中共享组件逻辑的三种方式
Feb 02 Javascript
Echarts之悬浮框中的数据排序问题
Nov 08 #Javascript
Jquery和CSS实现选择框重置按钮功能
Nov 08 #jQuery
基于React Native 0.52实现轮播图效果
Aug 25 #Javascript
详解webpack打包后如何调试的方法步骤
Nov 07 #Javascript
微信小程序列表中item左滑删除功能
Nov 07 #Javascript
Angular 实现输入框中显示文章标签的实例代码
Nov 07 #Javascript
VueCli3构建TS项目的方法步骤
Nov 07 #Javascript
You might like
php addslashes和mysql_real_escape_string
2010/01/24 PHP
在VS2008中编译MYSQL5.1.48的方法
2010/07/03 PHP
php 学习资料零碎东西
2010/12/04 PHP
tp5框架的增删改查操作示例
2019/10/31 PHP
jquery 防止表单重复提交代码
2010/01/21 Javascript
某人初学javascript的时候写的学习笔记
2010/12/30 Javascript
潜说js对象和数组
2011/05/25 Javascript
非常有用的40款jQuery 插件推荐(系列二)
2011/12/25 Javascript
setTimeout和setInterval的深入理解
2013/11/08 Javascript
JavaScript中的6种运算符总结
2014/10/16 Javascript
jQuery 判断图片是否加载完成方法汇总
2015/08/10 Javascript
移动手机APP手指滑动切换图片特效附源码下载
2015/11/30 Javascript
JS+CSS实现鼠标经过弹出一个DIV框完整实例(带缓冲动画渐变效果)
2016/03/25 Javascript
node+vue实现用户注册和头像上传的实例代码
2017/07/20 Javascript
微信公众号网页分享功能开发的示例代码
2020/05/27 Javascript
[01:51]DAC趣味视频-如何成为职业选手.mp4
2017/04/02 DOTA
Python使用metaclass实现Singleton模式的方法
2015/05/05 Python
Python实时获取cmd的输出
2015/12/13 Python
Python Pexpect库的简单使用方法
2019/01/29 Python
对python中字典keys,values,items的使用详解
2019/02/03 Python
解决Django生产环境无法加载静态文件问题的解决
2019/04/23 Python
Numpy对数组的操作:创建、变形(升降维等)、计算、取值、复制、分割、合并
2019/08/28 Python
Python列表原理与用法详解【创建、元素增加、删除、访问、计数、切片、遍历等】
2019/10/30 Python
python利用pytesseract 实现本地识别图片文字
2020/12/14 Python
5分钟实现Canvas鼠标跟随动画背景
2019/11/18 HTML / CSS
中文系师范生自荐信
2013/10/01 职场文书
仓管岗位职责范本
2014/02/08 职场文书
大学学风建设方案
2014/05/04 职场文书
新闻学专业求职信
2014/07/28 职场文书
美德少年事迹材料1000字
2014/08/21 职场文书
老龙头导游词
2015/02/11 职场文书
2015年办公室工作总结范文
2015/03/31 职场文书
阿凡达观后感
2015/06/10 职场文书
珍爱生命主题班会
2015/08/13 职场文书
机械原理课程设计心得体会
2016/01/15 职场文书
Vue如何实现组件间通信
2021/05/15 Vue.js