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 相关文章推荐
浅析jQuery中常用的元素查找方法总结
Jul 04 Javascript
jQuery表单美化插件jqTransform使用详解
Apr 12 Javascript
js动态生成Html元素实现Post操作(createElement)
Sep 14 Javascript
javascript中checkbox使用方法实例演示
Nov 19 Javascript
jQuery焦点图左右转换效果
Dec 12 Javascript
javascript输出AscII码扩展集中的字符方法
Dec 26 Javascript
jQuery插件artDialog.js使用与关闭方法示例
Oct 09 jQuery
使用layui+ajax实现简单的菜单权限管理及排序的方法
Sep 10 Javascript
微信小程序防止多次点击跳转和防止表单组件输入内容多次验证功能(函数防抖)
Sep 19 Javascript
JavaScript使用localStorage存储数据
Sep 25 Javascript
vue+vant-UI框架实现购物车的复选框全选和反选功能
Nov 05 Javascript
微信小程序清空输入框信息与实现屏幕往上滚动的示例代码
Jun 23 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
基于mysql的bbs设计(一)
2006/10/09 PHP
ECMall支持SSL连接邮件服务器的配置方法详解
2014/05/19 PHP
php导出csv格式数据并将数字转换成文本的思路以及代码分享
2014/06/05 PHP
PHP判断浏览器、判断语言代码分享
2015/03/05 PHP
利用PHP如何写APP接口详解
2016/08/23 PHP
PHP封装返回Ajax字符串和JSON数组的方法
2017/02/17 PHP
PHP基于GD库实现的生成图片缩略图函数示例
2017/07/05 PHP
Laravel实现短信注册的示例代码
2018/05/29 PHP
php生成HTML文件的类方法
2019/10/11 PHP
javascript各种复制代码收集
2008/09/20 Javascript
jQuery对下拉框,单选框,多选框的操作
2014/02/21 Javascript
js简单的表格添加行和删除行操作示例
2014/03/31 Javascript
javascript消除window.close()的提示窗口
2015/05/20 Javascript
深入理解jQuery 事件处理
2016/06/14 Javascript
jquery.guide.js新版上线操作向导镂空提示jQuery插件(推荐)
2017/05/20 jQuery
深入理解Vue官方文档梳理之全局API
2017/11/22 Javascript
微信小程序如何获取用户收货地址
2018/11/27 Javascript
Moment.js实现多个同时倒计时
2019/08/26 Javascript
Vue 实现一个简单的鼠标拖拽滚动效果插件
2020/12/10 Vue.js
[02:41]DOTA2英雄基础教程 冥魂大帝
2014/01/16 DOTA
[03:08]Ti4观战指南上
2014/07/07 DOTA
Python简单计算文件夹大小的方法
2015/07/14 Python
python实现斐波那契数列的方法示例
2017/01/12 Python
Python爬虫抓取代理IP并检验可用性的实例
2018/05/07 Python
python中计算一个列表中连续相同的元素个数方法
2018/06/29 Python
python机器学习库scikit-learn:SVR的基本应用
2019/06/26 Python
如何在Django项目中引入静态文件
2019/07/26 Python
Python 爬取必应壁纸的实例讲解
2020/02/24 Python
用Python开发app后端有优势吗
2020/06/29 Python
HTML5 embed 标签使用方法介绍
2013/08/13 HTML / CSS
欧迪办公美国官网:Office Depot
2016/08/22 全球购物
印刷工程专业应届生求职信
2013/09/29 职场文书
在校学生职业规划范文
2014/01/08 职场文书
晚宴邀请函范文
2014/01/15 职场文书
试用期自我鉴定范文
2014/03/20 职场文书
揭牌仪式策划方案
2014/05/28 职场文书