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 相关文章推荐
XML+XSL 与 HTML 两种方案的结合
Apr 22 Javascript
javascript 文件的同步加载与异步加载实现原理
Dec 13 Javascript
javascript生成json数据简单示例分享
Feb 14 Javascript
js兼容pc端浏览器并有多种弹出小提示的手机端浮层控件实例
Apr 29 Javascript
js实现的星星评分功能函数
Dec 09 Javascript
开启BootStrap学习之旅
May 04 Javascript
设计模式中的facade外观模式在JavaScript开发中的运用
May 18 Javascript
Vue.js鼠标悬浮更换图片功能
May 17 Javascript
详解React-Router中Url参数改变页面不刷新的解决办法
May 08 Javascript
ES6 Promise对象概念及用法实例详解
Oct 15 Javascript
Vue v-bind动态绑定class实例方法
Jan 15 Javascript
详解CocosCreator项目结构机制
Apr 14 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源码之 ext/mysql扩展部分
2009/07/17 PHP
php随机输出名人名言的代码
2012/10/07 PHP
php中如何使对象可以像数组一样进行foreach循环
2013/08/09 PHP
PHP面向对象教程之自定义类
2014/06/10 PHP
PHP中生成UUID自定义函数分享
2015/06/10 PHP
CI(CodeIgniter)模型用法实例分析
2016/01/20 PHP
Symfony2学习笔记之插件格式分析
2016/03/17 PHP
php实现图片以base64显示的方法
2016/10/13 PHP
laravel 配置路由 api和web定义的路由的区别详解
2019/09/03 PHP
语义化 H1 标签
2008/01/14 Javascript
javascript自动改变文字大小和颜色的效果的小例子
2013/08/02 Javascript
JS获取当前网页大小以及屏幕分辨率等
2014/09/05 Javascript
js+CSS实现弹出居中背景半透明div层的方法
2015/02/26 Javascript
JavaScript中捕获与冒泡详解及实例
2017/02/03 Javascript
JavaScript实现图片拖曳效果
2017/09/08 Javascript
vue父组件向子组件动态传值的两种方法
2017/11/11 Javascript
Bootstrap 实现表格样式、表单布局的实例代码
2018/12/09 Javascript
elementUI Tree 树形控件的官方使用文档
2019/04/25 Javascript
nodejs中各种加密算法的实现详解
2019/07/11 NodeJs
Python实现带百分比的进度条
2016/06/28 Python
Python向MySQL批量插数据的实例讲解
2018/03/31 Python
Python中一行和多行import模块问题
2018/04/01 Python
linux环境中没有网络怎么下载python
2019/07/07 Python
python2与python3爬虫中get与post对比解析
2019/09/18 Python
Python实现自动打开电脑应用的示例代码
2020/04/17 Python
Python创建临时文件和文件夹
2020/08/05 Python
通过HTML5规范搞定i、em、b、strong元素的区别
2017/03/04 HTML / CSS
印度网上购物首选目的地:Flipkart
2016/08/01 全球购物
携程旅行网:中国领先的在线旅行服务公司
2017/02/17 全球购物
俄罗斯马克西多姆家居用品网上商店:Максидом
2020/02/06 全球购物
BannerBuzz加拿大:在线定制横幅印刷、广告和标志
2020/03/10 全球购物
安全演讲稿大全
2014/05/09 职场文书
鸡毛信观后感
2015/06/11 职场文书
优秀党员主要事迹材料
2015/11/04 职场文书
Java多条件判断场景中规则执行器的设计
2021/06/26 Java/Android
Python if else条件语句形式详解
2022/03/24 Python