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 相关文章推荐
解决3.01版的jquery.form.js中文乱码问题的解决方法
Mar 08 Javascript
让低版本浏览器支持input的placeholder属性(js方法)
Apr 03 Javascript
ECMAScript6中Set/WeakSet详解
Jun 12 Javascript
JQuery中DOM事件冒泡实例分析
Jun 13 Javascript
13个PHP函数超实用
Oct 21 Javascript
JavaScript下的时间格式处理函数Date.prototype.format
Jan 27 Javascript
AngularJS入门教程之AngularJS模型
Apr 18 Javascript
jQuery中设置form表单中action值的实现方法
May 25 Javascript
AngularJS Phonecat实例讲解
Nov 21 Javascript
JS函数节流和函数防抖问题分析
Dec 18 Javascript
vue2.0 computed 计算list循环后累加值的实例
Mar 07 Javascript
原生js+css实现tab切换功能
Sep 17 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简单系统查询模块代码打包下载
2008/06/07 PHP
php获取用户IPv4或IPv6地址的代码
2012/11/15 PHP
PHP在引号前面添加反斜杠(PHP去除反斜杠)
2013/09/28 PHP
getJSON跨域SyntaxError问题分析
2014/08/07 PHP
Yii入门教程之Yii安装及hello world
2014/11/25 PHP
详谈symfony window下的安装 安装时候出现的问题以及解决方法
2017/09/28 PHP
js对象关系图 方便dom操作
2012/03/18 Javascript
JavaScript基础知识之数据类型
2012/08/06 Javascript
JS中实现replaceAll的方法(实例代码)
2013/11/12 Javascript
基于MVC4+EasyUI的Web开发框架形成之旅之界面控件的使用
2015/12/16 Javascript
jQuery+css实现的tab切换标签(兼容各浏览器)
2016/01/28 Javascript
js获取所有checkbox的值的简单实例
2016/05/30 Javascript
Angular 页面跳转时传参问题
2016/08/01 Javascript
15款最好的Bootstrap在线编辑器
2016/08/03 Javascript
javascript回调函数的概念理解与用法分析
2017/05/27 Javascript
基于JavaScript实现飘落星星特效
2017/08/10 Javascript
jQuery实现的粘性滚动导航栏效果实例【附源码下载】
2017/10/19 jQuery
JS限制输入框输入的实现代码
2018/07/02 Javascript
关于RxJS Subject的学习笔记
2018/12/05 Javascript
vue两组件间值传递 $router.push实现方法
2019/05/15 Javascript
Python中使用MELIAE分析程序内存占用实例
2015/02/18 Python
Python3实现的爬虫爬取数据并存入mysql数据库操作示例
2018/06/06 Python
Python爬取知乎图片代码实现解析
2019/09/17 Python
Python读写压缩文件的方法
2020/07/30 Python
python实现马丁策略回测3000只股票的实例代码
2021/01/22 Python
HTML5 Canvas中使用路径描画二阶、三阶贝塞尔曲线
2015/01/01 HTML / CSS
波兰最大的儿童服装连锁店之一:5.10.15.
2018/02/11 全球购物
泰坦健身器材:Titan Fitness
2018/02/13 全球购物
名人珠宝设计师:Melinda Maria Jewelry
2019/03/06 全球购物
通用求职信范文模板分享
2013/12/27 职场文书
教师民族团结演讲稿
2014/08/27 职场文书
新闻人物通讯稿
2014/10/09 职场文书
2014年采购部工作总结
2014/11/20 职场文书
常住证明范本
2015/06/23 职场文书
中国梦宣传标语口号
2015/12/26 职场文书
微信小程序中使用vant框架的具体步骤
2022/02/18 Javascript