likes
comments
collection
share

Mockjs入门级操作 && 案例操作(实现增删改查功能) (二)

作者站长头像
站长
· 阅读数 24

提示:上篇文章里讲解了 mockjs 的一些入门操作,及简单案例演示. 这篇文章将结合项目实现列表的增删改查功能.如有不当之处 欢迎指正


前言

日常开发中,curd是每个项目都有的基础功能.下面实现在独立于后端时进行curd功能的实现


提示:以下是本篇文章正文内容,下面案例可供参考 如有不当之处 欢迎指正

一、回顾mockjs在vue项目中的基础使用步骤

  1. mock/list/index文件中对接口数据进行模拟;
  2. api/list/index 文件中封装axios请求
  3. .vue组件中调用接口,获取模拟数据;

二、增删改查功能实现

以下关于组件的创建不做过多赘述

1.增删改查 -- 查

1.创建views/list/index.vue :

  1. 完成基本的分页列表布局; Mockjs入门级操作 && 案例操作(实现增删改查功能) (二)

2.模拟 查询功能 的接口

  1. 生成列表的数据
  2. 生成 查询 功能的接口 ps :此处的 接口地址 需要与 axios 中封装的接口地址一致;
// 列表模拟数据生成
//'userList|55': 数组的长度为55
const data = Mock.mock({
  'userList|55': [
    {
      id: '@increment',
      name: '@cname()',
      address: '@city(true)',
      date: '@date(yyyy-MM-dd)'
    }
  ]
})

data数据: 随机生成了长度为55的数组 Mockjs入门级操作 && 案例操作(实现增删改查功能) (二)

生成 查询 功能的接口 :

  1. 此处 返回的格式需要和后端商讨一致. 2.options : 可以接收到 本次请求的 Ajax 选项集 RegExp : 对接口地址进行正则匹配.
// 生成 查询 功能的接口
Mock.mock(RegExp('mock/userList'), 'get', (options) => {
  console.log(options)
  return {
    code: 200,
    success: true,
    message: '获取用户列表成功',
    data: data.userList,
    totalPage: data.userList.length
  }
})

3.封装axios的列表接口

export const getUserListAPI = (params) => {
  return request({
    url: 'mock/userList',  // 此处的接口地址与模拟的 mockjs 接口地址一致
    method: 'get',
    params
  })
}

4.views/list/index.vue中调用接口

   async getUserList() {
      const res = await getUserListAPI({
        pageSize: this.pageSize,
        currentPage: this.currentPage
      })
      this.tableData = res.data
      this.total = res.totalPage
      console.log(res, 'res')
    }

因为涉及到分页功能,所以需要传入 pageSize , currentPage 两个参数; 这时候再反过来看 options中获取到的数据,以及接口响应后我们模拟的返回数据 Mockjs入门级操作 && 案例操作(实现增删改查功能) (二) Mockjs入门级操作 && 案例操作(实现增删改查功能) (二)

5. 处理分页功能

分页功能的处理 实际上就是对生成的data数据进行处理;

  1. 从 options.url中解析出 传过来的参数值 (pageSize,currentPage)
  2. 根据 pageSize(每页条数) currentPage(当前页) 处理 data数据
  3. 获取数据的起始值
  4. 获取数据的终止值
  5. 获取当前的总页数
  6. 返回新的数组

1) options.url 解析参数值 :

这里实际就是对 url 进行拆分,然后再匹配传入的值

// 处理get请求的url参数  "/api/api/mock/userList?pageSize=10&currentPage=1"
const getQuery = (url, name) => {
  const isFind = url.indexOf(name) !== -1
  if (isFind) {
    const queryArr = url.split('?')[1].split('&')
    for (let i = 0; i < queryArr.length; i++) {
      const result = queryArr[i].split('=')
      if (result[0] === name) {
        return result[1]
      }
    }
  }
  return null
}

2) 对data数据进行处理

完善mockjs的接口

Mock.mock(RegExp('mock/userList'), 'get', (options) => {
 	// 根据url解析出pageSize的值
  const pageSize = getQuery(options.url, 'pageSize')
  	// 根据url解析出currentPage的值
  const currentPage = getQuery(options.url, 'currentPage') 
  /**
   * 对返回的数组进行处理 (即实现分页效果)
   * 1.获取起始值  : pageSize=1 currentPage=10 即 0(索引)  
     计算公式 : (pageSize-1)*currentPage
   * 2.获取终止值  : pageSize=1 currentPage=10 即 9(索引)  
     计算公式 : pageSize*currentPage (不-1,是因为使用splice进行截取;)
   * 3.如当前页码超出总页码,则返回 [] ;  
     计算公式 : totalPage=Math.ceil(data.length/currentPage)
   */
  const startIndex = (currentPage - 1) * pageSize
  const endIndex = pageSize * currentPage
  const totalPage = Math.ceil(data.userList.length / pageSize)

  const newDataArr =
    currentPage > totalPage ? [] : data.userList.slice(startIndex, endIndex)

  return {
    code: 200,
    success: true,
    message: '获取用户列表成功',
    data: newDataArr,
    totalPage: data.userList.length
  }
})

6.完善list.vue页面的分页功能,使pageSize,currentPage 动态化

 // 分页
    handleSizeChange(val) {
      this.pageSize = val
      this.getUserList()
    },
    handleCurrentChange(val) {
      this.currentPage = val
      this.getUserList()
    },
  async getUserList() {
      const { data, totalPage } = await getUserListAPI({
        pageSize: this.pageSize,
        currentPage: this.currentPage
      })
      this.tableData = data
      this.total = totalPage
    }

分页功能展示 : Mockjs入门级操作 && 案例操作(实现增删改查功能) (二)

2.增删改查 -- 增

1. mockjs 模拟 新增 接口 ,封装axios的新增接口

  1. mockjs 模拟 新增 接口 :

post请求,请求参数存在请求体里面;

Mock.mock(RegExp('mock/addUser'), 'post', (options) => {
  console.log(options, 'options')
  return {
    code: 200,
    success: true,
    message: '用户添加成功'
  }
})```

 2. 封装axios的新增接口:
```javascript
export const addUserAPI = (data) => {
  return request({
    url: 'api/mock/addUser',
    method: 'post',
    data
  })
}

2. 创建 views/list/modules/listDialog.vue

  1. 完成基本的布局.

新增和编辑是共用的这个dialog弹框,所以弹框的title和btnText都是动态化的;

Mockjs入门级操作 && 案例操作(实现增删改查功能) (二) 2. views/list/index.vue中引入listDialog ,实现弹框的显示隐藏功能:

// @handleOk="handleOk" --接收子组件传入的表单数据  
// @ok="modelFormOk" 子组件修改完成,触发重新渲染列表
 <list-dialog  ref="dialogFormVisible"  @handleOk="handleOk"  @ok="modelFormOk"/>
  // 新增
    handleAdd() {
      this.$refs.dialogFormVisible.add()
    },

listDialog :

  add() {
      this.dialogFormVisible = true
      this.btnText = '新增用户'
      this.ruleForm = {}
    },
//弹窗关闭事件
 onClose() {
      this.dialogFormVisible = false
    }
  1. 点击新增用户时,将获取的表单数据传入父组件中
 submitForm(formName) {
      this.$refs[formName].validate(async (valid) => {
        if (valid) {
          this.$emit('handleOk', this.ruleForm)
        } else {
          return false
        }
      })

2.获取子组件传参,调用新增接口

 async handleOk(formData) {
      const res = await addUserAPI(formData)
      if (res.success) {
        this.$message({
          message: res.message,
          type: 'success'
        })
        this.$refs.dialogFormVisible.onClose() // 关闭弹窗
        this.getUserList()  // 重新加载列表
      }
    },

3. 完善 mockjs 的 新增接口

此时已经将获取的表单数据传入了接口中, 这时再来看 post 传参 和 get 传参的不同之处,以及对data数据的处理;

post请求的参数 可以直接在 options.body中获取 因为获取到的数据是字符串形式("{"name":"张三","address":"成都","date":"2022-03-01"}"),需要使用JSON.parse()进行转换 将当前传入的参数追加进 data列表中.

Mock.mock(RegExp('mock/addUser'), 'post', (options) => {
  const params = JSON.parse(options.body)
  data.userList.unshift(
    Mock.mock({
      id: '@increment',
      name: params.name,
      address: params.address,
      date: params.date
    })
  )
  return {
    code: 200,
    success: true,
    message: '用户添加成功'
  }
})

新增功能展示 : Mockjs入门级操作 && 案例操作(实现增删改查功能) (二)

3.增删改查 -- 改

1. mockjs模拟 编辑 接口 ,封装 axios 的 编辑 接口

1.mockjs模拟 编辑 接口

获取 传入的 id 值,进行匹配,重新赋值;

Mock.mock(RegExp('mock/editUser'), 'post', (options) => {
  const params = JSON.parse(options.body)
  for (let i = 0; i < data.userList.length; i++) {
    if (data.userList[i].id === params.id) {
      data.userList[i] = params
    }
  }
  return {
    code: 200,
    success: true,
    message: '用户修改成功'
  }
})

2.封装 axios 的 编辑 接口

export const editUserAPI = (data) => {
  return request({
    url: 'api/mock/editUser',
    method: 'post',
    data
  })
}

2.点击编辑 , 将当前行数据传入listDialog

handleEdit(record) {
      this.$refs.dialogFormVisible.edit(record)
    },

3. listDialog 进行数据回显

  edit(record) {
      this.dialogFormVisible = true
      this.ruleForm = Object.assign({}, record)
      this.btnText = '编辑用户'
    },

此处效果展示 : Mockjs入门级操作 && 案例操作(实现增删改查功能) (二)

Mockjs入门级操作 && 案例操作(实现增删改查功能) (二)

4. 点击编辑用户时,调用编辑接口

实际上 ,此处和新增用户触发的是同一个方法 判断当前表单数据是否存在 id 值, 如果存在则是编辑, 不存在则是新增; 存在时 调用编辑接口 修改完成后,通知父组件已经完成修改,重新渲染列表

 submitForm(formName) {
      this.$refs[formName].validate(async (valid) => {
        if (valid) {
          if (!this.ruleForm.id) {
            this.$emit('handleOk', this.ruleForm)
          }
          const res = await editUserAPI(this.ruleForm)
          if (res.success) {
            this.$message({
              message: res.message,
              type: 'success'
            })
            this.$emit('ok') // 完成修改,通知父组件重新渲染列表;
            this.onClose()
          }
        } else {
          return false
        }
      })
    },

父组件 重新渲染事件 :

 // 编辑
    modelFormOk() {
      this.getUserList()
    },

4.增删改查 -- 删

1.mockjs 模拟 删除 接口 , 封装 axios 的 删除接口

  1. mockjs 模拟 删除 接口

获取传入的 id 值 ,进行匹配,查找到当前的索引; 通过Array.splice() 方法 删除当前数据

Mock.mock(RegExp('mock/deleteUser'), 'post', (options) => {
  const params = JSON.parse(options.body)
  const deleteIndex = data.userList.findIndex((item) => {
    return item.id === params.id
  })
  data.userList.splice(deleteIndex, 1)

  return {
    code: 200,
    success: true,
    message: '用户删除成功'
  }
})
  1. 封装 axios 的 删除接口
export const deleteUserAPI = (data) => {
  return request({
    url: 'api/mock/deleteUser',
    method: 'post',
    data
  })
}

2.点击删除时, 调用删除接口

 // 删除
    async handleDelete(record) {
      const res = await deleteUserAPI(record)
      if (res.success) {
        this.$message({
          message: res.message,
          type: 'success'
        })
        this.getUserList()
      }
    },

效果展示 : Mockjs入门级操作 && 案例操作(实现增删改查功能) (二)

三. 完整代码 及 功能实现效果展示

1. mock/list/index

import Mock from 'mockjs'

// 处理get请求的url参数
const getQuery = (url, name) => {
  const isFind = url.indexOf(name) !== -1
  if (isFind) {
    const queryArr = url.split('?')[1].split('&')
    for (let i = 0; i < queryArr.length; i++) {
      const result = queryArr[i].split('=')
      if (result[0] === name) {
        return result[1]
      }
    }
  }
  return null
}

const data = Mock.mock({
  'userList|55': [
    {
      id: '@increment',
      name: '@cname()',
      address: '@city(true)',
      date: '@date(yyyy-MM-dd)'
    }
  ]
})

Mock.mock(RegExp('mock/userList'), 'get', (options) => {
  const pageSize = getQuery(options.url, 'pageSize') // 根据url解析出pageSize的值
  const currentPage = getQuery(options.url, 'currentPage') // 根据url解析出currentPage的值
  /**
   * 对返回的数组进行处理 (即实现分页效果)
   * 1.获取起始值  : pageSize=1 currentPage=10 即 0(索引)  计算公式 : (pageSize-1)*currentPage
   * 2.获取终止值  : pageSize=1 currentPage=10 即 9(索引)  计算公式 : pageSize*currentPage (不-1,是因为使用splice进行截取;)
   * 3.如当前页码超出总页码,则返回 [] ;  totalPage=Math.ceil(data.length/currentPage)
   */
  const startIndex = (currentPage - 1) * pageSize
  const endIndex = pageSize * currentPage
  const totalPage = Math.ceil(data.userList.length / pageSize)

  const newDataArr =
    currentPage > totalPage ? [] : data.userList.slice(startIndex, endIndex)

  return {
    code: 200,
    success: true,
    message: '获取用户列表成功',
    data: newDataArr,
    totalPage: data.userList.length
  }
})

Mock.mock(RegExp('mock/addUser'), 'post', (options) => {
  const params = JSON.parse(options.body)
  data.userList.unshift(
    Mock.mock({
      id: '@increment',
      name: params.name,
      address: params.address,
      date: params.date
    })
  )
  return {
    code: 200,
    success: true,
    message: '用户添加成功'
  }
})

Mock.mock(RegExp('mock/deleteUser'), 'post', (options) => {
  const params = JSON.parse(options.body)
  const deleteIndex = data.userList.findIndex((item) => {
    return item.id === params.id
  })
  data.userList.splice(deleteIndex, 1)

  return {
    code: 200,
    success: true,
    message: '用户删除成功'
  }
})

Mock.mock(RegExp('mock/editUser'), 'post', (options) => {
  const params = JSON.parse(options.body)
  for (let i = 0; i < data.userList.length; i++) {
    if (data.userList[i].id === params.id) {
      data.userList[i] = params
    }
  }
  return {
    code: 200,
    success: true,
    message: '用户修改成功'
  }
})

2. api/list/index

import request from '@/utils/request.js'

export const getUserListAPI = (params) => {
  return request({
    url: 'api/mock/userList',
    method: 'get',
    params
  })
}

export const addUserAPI = (data) => {
  return request({
    url: 'api/mock/addUser',
    method: 'post',
    data
  })
}

export const deleteUserAPI = (data) => {
  return request({
    url: 'api/mock/deleteUser',
    method: 'post',
    data
  })
}

export const editUserAPI = (data) => {
  return request({
    url: 'api/mock/editUser',
    method: 'post',
    data
  })
}

3.views/list/index.vue

<template>
  <div class="user-list-container">
    <el-button type="primary" icon="el-icon-plus" @click="handleAdd">
      新增用户
    </el-button>
    <el-table :data="tableData" style="width: 100%" height="450">
      <el-table-column type="index" label="序号" width="50"> </el-table-column>
      <el-table-column prop="date" label="日期"> </el-table-column>
      <el-table-column prop="name" label="姓名"> </el-table-column>
      <el-table-column prop="address" label="地址"> </el-table-column>
      <el-table-column label="操作" width="100">
        <template slot-scope="scope">
          <el-button @click="handleEdit(scope.row)" type="text" size="small">
            编辑
          </el-button>
          <el-popconfirm
            title="确定删除此用户吗?"
            @confirm="handleDelete(scope.row)"
            confirm-button-text="确定"
            cancel-button-text="取消"
          >
            <el-button type="text" size="small" slot="reference">
              删除
            </el-button>
          </el-popconfirm>
        </template>
      </el-table-column>
    </el-table>
    <div class="pagination">
      <el-pagination
        @size-change="handleSizeChange"
        @current-change="handleCurrentChange"
        :current-page="currentPage"
        :page-sizes="[10, 20, 30, 40]"
        :page-size="pageSize"
        layout="total, sizes, prev, pager, next, jumper"
        :total="total"
      >
      </el-pagination>
    </div>
    <list-dialog
      ref="dialogFormVisible"
      @handleOk="handleOk"
      @ok="modelFormOk"
    />
  </div>
</template>

<script>
import { getUserListAPI, addUserAPI, deleteUserAPI } from '@/apis/user.js'
import ListDialog from './modules/ListDialog.vue'

export default {
  components: { ListDialog },
  data() {
    return {
      tableData: [],
      currentPage: 1,
      pageSize: 10,
      total: null
    }
  },
  methods: {
    handleEdit(record) {
      this.$refs.dialogFormVisible.edit(record)
    },
    // 新增
    handleAdd() {
      this.$refs.dialogFormVisible.add()
    },
    async handleOk(formData) {
      const res = await addUserAPI(formData)
      if (res.success) {
        this.$message({
          message: res.message,
          type: 'success'
        })
        this.$refs.dialogFormVisible.onClose()
      }
      this.getUserList()
    },

    // 编辑
    modelFormOk() {
      this.getUserList()
    },

    // 删除
    async handleDelete(record) {
      const res = await deleteUserAPI(record)
      if (res.success) {
        this.$message({
          message: res.message,
          type: 'success'
        })
        this.getUserList()
      }
    },
    // 分页
    handleSizeChange(val) {
      this.pageSize = val
      this.getUserList()
    },
    handleCurrentChange(val) {
      this.currentPage = val
      this.getUserList()
    },
    async getUserList() {
      const { data, totalPage } = await getUserListAPI({
        pageSize: this.pageSize,
        currentPage: this.currentPage
      })
      this.tableData = data
      this.total = totalPage
    }
  },
  created() {
    this.getUserList()
  }
}
</script>

<style lang="scss" scoped>
.pagination {
  margin-top: 10px;
  text-align: right;
}
</style>

4.

<template>
  <el-dialog :title="btnText" :visible.sync="dialogFormVisible" width="450px">
    <el-form
      :model="ruleForm"
      :rules="rules"
      ref="ruleForm"
      label-width="100px"
      class="demo-ruleForm"
    >
      <el-form-item label="姓名" prop="name">
        <el-input v-model="ruleForm.name" style="width: 200px"></el-input>
      </el-form-item>
      <el-form-item label="地址" prop="address">
        <el-input v-model="ruleForm.address" style="width: 200px"></el-input>
      </el-form-item>
      <el-form-item label="日期" required>
        <el-col :span="11">
          <el-form-item prop="date">
            <el-date-picker
              v-model="ruleForm.date"
              placeholder="选择日期"
              value-format="yyyy-MM-dd"
            >
            </el-date-picker>
          </el-form-item>
        </el-col>
      </el-form-item>

      <el-form-item>
        <el-button type="primary" @click="submitForm('ruleForm')">
          {{ btnText }}
        </el-button>
        <el-button @click="onClose">取消</el-button>
      </el-form-item>
    </el-form>
  </el-dialog>
</template>

<script>
import { editUserAPI } from '@/apis/user'
export default {
  data() {
    return {
      dialogFormVisible: false,
      ruleForm: {
        name: '',
        address: '',
        date: ''
      },
      rules: {
        name: [
          { required: true, message: '请输入姓名', trigger: 'blur' },
          { min: 2, max: 5, trigger: 'blur' }
        ],
        address: [
          { required: true, message: '请输入居住地址', trigger: 'blur' }
        ],
        date: [
          {
            required: true,
            message: '请选择日期',
            trigger: 'blur'
          }
        ]
      },
      btnText: null
    }
  },
  methods: {
    submitForm(formName) {
      this.$refs[formName].validate(async (valid) => {
        if (valid) {
          if (!this.ruleForm.id) {
            this.$emit('handleOk', this.ruleForm)
          }
          const res = await editUserAPI(this.ruleForm)
          if (res.success) {
            this.$message({
              message: res.message,
              type: 'success'
            })
            this.$emit('ok')
            this.onClose()
          }
        } else {
          return false
        }
      })
    },

    add() {
      this.dialogFormVisible = true
      this.btnText = '新增用户'
      this.ruleForm = {}
    },
    edit(record) {
      this.dialogFormVisible = true
      this.ruleForm = Object.assign({}, record)
      this.btnText = '编辑用户'
    },
    onClose() {
      this.dialogFormVisible = false
    }
  }
}
</script>

<style lang="less" scoped></style>

5. 功能实现效果展示 :

Mockjs入门级操作 && 案例操作(实现增删改查功能) (二)


总结

提示:以上 使用 mockjs 前端独立实现 curd 功能 的完整代码 ,如有不当欢迎指正 以上的编辑功能可以在写在listDialog组件中 (因为我已经写完了就懒得修改了);