webpack4+express+mongodb+vue 實現增刪改查


在講解之前,我們先來看看效果如下所示:

1)整個頁面的效果如下:

2) 新增數據效果如下:

3) 新增成功如下:

4) 編輯數據效果如下:

 

5) 編輯成功效果如下:

 

6) 刪除數據效果如下:

 

7) 刪除成功效果如下:

 

8) 查詢效果如下:

 

如上的效果,下面我們還是和之前一樣,先看看我們整個項目的架構如下所示:

### 目錄結構如下:
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 文件內部實現增刪改查操作。

如果對mongodb數據庫相關的知識點不是很熟悉的話,可以先看下我之前寫的一些關於mongodb文章(https://www.cnblogs.com/tugenhua0707/category/1240772.html), 先在本地把數據庫搭建起來后,再慢慢學習哦,我這邊文章實現 vue+mongodb 實現增刪改查也是基於上面這些文章的基礎之上來進行的,特別是居於這篇 使用Mongoose類庫實現簡單的增刪改查
(https://www.cnblogs.com/tugenhua0707/p/9256605.html) 來進行的,增刪改查操作及使用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://www.cnblogs.com/tugenhua0707/p/9256605.html)如下代碼:

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://www.cnblogs.com/tugenhua0707/p/9256605.html):

// 引入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代碼


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM