• Vue + Element-UI —— 项目实战(七)


    系列文章目录

    Vue + Element-UI —— 项目实战(零)(项目概述)

    Vue + Element-UI —— 项目实战(一)

    Vue + Element-UI —— 项目实战(二)

    Vue + Element-UI —— 项目实战(三)

    Vue + Element-UI —— 项目实战(四)

    Vue + Element-UI —— 项目实战(五)

    Vue + Element-UI —— 项目实战(六)

    Vue + Element-UI —— 项目实战(七)

    Vue + Element-UI —— 项目实战(八)(完结)



    七、项目实战七

    Ⅰ、用户管理页面

    1. Form 表单

    使用的是 el-form 组件进行相关配置

    1. 在 components 文件夹下创建 CommonForm.vue 文件
    1. 表单中需要引入 Input 组件(文本框)、Select 组件(选择)、Option 组件(Select 组件的下拉值)、Switch 组件、DatePicker 组件(日期)
    	<template>
    	  <!-- 通过ref可以拿到form实例 -->
    	  <!-- :model与form表单实现双向数据绑定,:inline是表单内容的布局方式,为true时一行多列 -->
    	  <el-form ref="form" label-width="100px" :model="form" :inline=true>
    	    <!-- 表单域 -->
    	    <el-form-item
    	      v-for="item in formLabel"
    	      :key="item.label"
    	      :label="item.label"
    	    >
    	      <!-- 渲染表单元素
    	           通过type属性区分 
    	           数据与表单组件进行双向数据绑定,拿到form数据下的item.model-->
    	      <!-- 姓名输入 -->
    	      <!-- item.type:用来区分表单组件中应该渲染什么组件 -->
    	      <el-input 
    	        v-if="item.type === 'input'"
    	        :placeholder="'请输入' + item.label"
    	        v-model="form[item.model]"
    	      ></el-input>
    	      <!-- 性别判断 -->
    	      <el-switch v-if="item.type === 'switch'" v-model="form[item.model]"></el-switch>
    	      <!-- 出生日期 -->
    	      <!-- value-format:日期格式定义 -->
    	      <el-date-picker 
    	        v-if="item.type === 'date'"
    	        type="date"
    	        value-format="yyyy-MM-dd"
    	        placeholder="选择日期"
    	        v-model="form[item.model]"
    	      ></el-date-picker>
    	      <!-- 性别下拉框 -->
    	      <el-select
    	        v-if="item.type === 'select'"
    	        placeholder="请选择"
    	        v-model="form[item.model]"
    	      >
    	        <!-- 下拉组件,两个选项:男/女
    	             opts是配置项,里面有是定义好的数据 -->
    	        <el-option
    	            v-for="item in item.options"
    	            :key="item.value"
    	            :label="item.label"
    	            :value="item.value"
    	        ></el-option>
    	      </el-select>
    	    </el-form-item>
    	    <!-- 如果当前的组件都不满足  -->
    	    <el-form-item>
    	        <slot>不符合条件</slot>
    	    </el-form-item>
    	  </el-form>
    	</template>
    	
    	<script> 
    	export default {
    	  name: "CommonForm",
    	  props: {
    	    formLabel: Array, //form相关配置的数据
    	    form: Object,  //外部组件传入数据,接收数据对其进行双向绑定
    	    inline: Boolean, //表单布局:单行/多行
    	  },
    	  data() {
    	    return {};
    	  },
    	};
    	</script>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    2. 用户列表页头部 & dialog 弹窗
    1. 用户列表页的呈现
    	<template>
    	  <div class="manage">
    	    <!-- 对话框 -->
    	    <!-- title:点击新增显示【新增用户】,点击编辑显示【更新用户】
    	         visible:是否显示Dialog,支持.sync修饰符【vue3-实现子组件与父组件的双向绑定,并且可以实现子组件同步修改父组件的值】-->
    	    <el-dialog
    	      :title="operateType === 'add' ? '新增用户' : '更新用户'"
    	      :visible.sync="isShow"
    	    >
    	      <common-form
    	        :formLabel="opertateFormLabel"
    	        :form="operateForm"
    	        :inline="true"
    	        ref="form"
    	      ></common-form>
    	      <!-- 给弹窗组件添加自定义底部 -->
    	      <div slot="footer" class="dialog-footer">
    	        <!-- 点击取消不展示dialog框 -->
    	        <el-button @click="isShow = false">取消</el-button>
    	        <!-- 点击确定,primary:主要按钮(蓝色),触发confirm方法 -->
    	        <el-button type="primary" @click="confirm">确定</el-button>
    	      </div>
    	    </el-dialog>
    	    <!-- 顶部 -->
    	    <div class="manage-header">
    	      <!-- 新增,点击添加人员信息,primary:信息类型的按钮(蓝色) -->
    	      <el-button type="primary" @click="addUser">+ 新增</el-button>
    	      <!-- 右侧的输入框 -->
    	      <common-form
    	        :formLabel="formLabel"
    	        :form="searchForm"
    	        :inline="true"
    	        ref="form"
    	      >
    	        <!-- 人员查询 -->
    	        <el-button type="primary" @click="getList(searchForm.keyword)">搜索</el-button>
    	      </common-form>
    	    </div>
    	    <!-- config:分页的配置数据 -->
    	    <common-table
    	      :tableData="tableData"
    	      :tableLabel="tableLabel"
    	      :config="config"
    	      @changePage="getList()"
    	      @edit="editUser"
    	      @del="delUser"
    	    ></common-table>
    	  </div>
    	</template>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    1. data 中的数据
    	operateType: "add",
        // dialog弹窗默认关闭
        isShow: false, 
        // 表单标签数据
        opertateFormLabel: [...],
        // 修改表单元素时会通过双向数据绑定修改父组件传递来的数据
        operateForm: {...},
        // 右侧输入框类型及配置
        formLabel: [...],
        // 要传入的数据【关键字】
        searchForm: {...},
        // table表格的数据
        tableData: [...],
        // table中列的配置数据
        tableLabel: [...],
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    1. 点击新增弹出 dialog 框
    	addUser() {
          // 点击新增弹出dialog框
          this.isShow = true;
          // 默认为新增
          this.operateType = "add";
          // 数据初始化:都为空
          this.operateForm = {
            name: "",
            addr: "",
            age: "",
            birth: "",
            sex: "",
          };
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    1. Flex 弹性布局
    	<style lang="less" scoped>
    	// 对新增和搜索框进行flex布局
    	.manage-header {
    	  display: flex;
    	  justify-content: space-between;
    	  align-items: center;
    	}
    	.common-table {
    	  margin-top: 35px;
    	  height: 465px;
    	}
    	</style>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    效果图

    在这里插入图片描述
    在这里插入图片描述

    3. 用户列表新增 & 新增+编辑接口调用
    1. ./user/index.vue 中添加方法,绑定到 dialog 弹窗的确定按钮,同于添加数据。
    	confirm() {
          // operateType的状态为编辑的时候
          if (this.operateType === "edit") {
            // mock模拟数据
            this.$http.post("/user/edit", this.operateForm).then((res) => {
              console.log(res);
              this.isShow = false;  //关闭弹窗
            });
            // 新增的逻辑
          } else {
            this.$http.post("/user/add", this.operateForm).then((res) => {
              console.log(res);
              this.isShow = false;  //关闭弹出
            });
          }
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    1. 在user.js 中定义了createUser 和 updateUser 方法,在mock.js 中拦截
    	// 语法:记录用于生成响应数据的函数。
    	// 当拦截到匹配 rurl 和 rtype 的 Ajax 请求时,
    	// 函数 function(options) 将被执行,并把执行结果作为响应数据返回。
    	Mock.mock( rurl?, rtype?, template|function( options ) )
    
    • 1
    • 2
    • 3
    • 4
    	import userApi from './mockServerData/user'
    	Mock.mock(/user\/add/, 'post', userApi.createUser) 
    	Mock.mock(/user\/edit/, 'post', userApi.updateUser)
    
    • 1
    • 2
    • 3

    用户添加

    在这里插入图片描述

    在这里插入图片描述

    4. 用户列表 table 组件的数据展示
    1. 在 components 中创建 CommonTable.vue 组件。
    1. 使用 Table 组件、TableColumn (表格的列) 组件、Pagination(分页) 组件,来搭建表格。
    	<template>
    	  <div class="common-table">
    	      <!-- stripe斑马条纹 -->
    	      <el-table :data="tableData" height="90%" stripe>
    	        <!-- 用tooltip显示超长的文案 -->
    	        <!-- :width 看看有没有这个宽度,如果有就用,没有用默认定义的 -->
    	        <el-table-column 
    	            show-overflow-tooltip
    	            v-for="item in tableLabel"
    	            :key="item.props"
    	            :label="item.label"
    	            :width="item.width ? item.width : 125"
    	        >
    	            <!-- 接收传入进来的插槽数据 -->
    	            <template slot-scope="scope">
    	                <!-- scope.row:用插槽拿到当前行row内置属性 -->
    	                <span>{{scope.row[item.prop]}}</span>
    	            </template>
    	        </el-table-column>
    	        <!-- 操作列 -->
    	        <el-table-column label="操作" min-width="180">
    	            <template slot-scope="scope">
    	                <!-- scope.row表示当前行的数据 -->
    	                <el-button size="mini" @click="handleEdit(scope.row)">编辑</el-button>
    	                <el-button size="mini" type="danger" @click="handleDelete(scope.row)">删除</el-button>
    	            </template>
    	            
    	        </el-table-column>
    	      </el-table>
    	
    	      <!-- 分页组件
    	           layout:组件布局,子组件名用逗号分隔
    	           :total: 总数据数量
    	           current-page.sync:当前页数
    	           current-change:改变分页数的回调函数
    	           page-size:每页显示个数
    	      -->
    	      <el-pagination
    	        class="pager"
    	        layout="prev, pager, next"
    	        :total="config.total"
    	        :current-page.sync="config.page"
    	        @current-change="changePage"
    	        :page-size="20"
    	      >
    	      </el-pagination>
    	  </div>
    	</template>
    	
    	<script>
    	export default {
    	    name:'CommonTable',
    	    props: {
    	        tableData: Array,  //表格的数据
    	        tableLabel: Array, //表格的首行的提示数据
    	        config: Object //用于传输总数据
    	    },
    	    data(){
    	        return{}
    	    },
    	    methods:{
    	        // row为当前分页的数据
    	        handleEdit(row) {
    	            this.$emit('edit', row) //拿到当前行的数据,向父组件传递
    	        },
    	        handleDelete(row) {
    	            this.$emit('del', row) //拿到当前行的数据,向父组件传递
    	        },
    	        changePage(page) {
    	            this.$emit('changePage', page) //拿到当前分页的数据,向父组件传递
    	        }
    	    }
    	};
    	</script>
    	
    	<style lang="less" scoped>
    	.common-table {
    	    height: calc(100% -62px);
    	    background-color: #fff;
    	    position: relative;
    	    .pager {
    	        position: absolute;
    	        bottom: 0;
    	        right: 20px;
    	    }
    	}
    	</style>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    1. 在 mock.js 中拦截
    	Mock.mock(/user\/getUser/, 'get', userApi.getUserList)
    
    • 1
    1. 在 data.js 中配置数据请求
    	export const getUser = (params) => {
    	    return axios.request({
    	        url: '/user/getUser', //接口的相关地址
    	        method: 'get',        //请求方式
    	        params
    	    })
    	}
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    1. 编辑、删除、显示表格数据、分页
    	methods:{
          // 编辑
          editUser(row){
            this.operateType = 'edit' 
            this.isShow = true
            // row表示当前行的数据
            this.operateForm = row //数据回写当前行的数据
          },
          // 删除
          delUser(row) {
            //通知栏组件
            this.$confirm("此操作将永久删除该组件,是否继续?", "提示", {
              confirmButtonText: "确认",
              cancelButtonText: "取消",
              type: "warning" //弹窗类型(警告)
            }).then(() => {
              const id = row.id 
              this.$http.post("/user/del", {
                params: {id}
              }).then(() => {
                // $message、$confirm 为ElementUI弹出框的相关属性
                this.$message({
                  type: 'success',
                  message: '删除成功'
                })
                this.getList()
              })
            })
          },
           // 显示表格数据,并进行分页
          getList(name = '') {
            this.config.loading = true  // 获取数据前给它一个loading
            name ? (this.config.page = 1) : ''  //分页名字存在初始页为1
            // 接口调用
            getUser({
              page: this.config.page,
              name
            }).then(res => {
              console.log('getUser', res);
              this.tableData = res.list.map(item => {
                item.sexLabel = item.sex === 0 ? '女' : '男'
                return item
              })
              this.config.total = res.count  //分页数据
              this.config.loading = false  //关闭loading
            })
          },
        },
        created() {
          // 页面加载就调用
          this.getList()
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52

    数据显示效果图

    在这里插入图片描述

    5. 剩余功能的实现
    1. 查询功能:拿到输入框的关键字
    	<el-button type="primary" @click="getList(searchForm.keyword)">搜索</el-button>
    
    • 1

    在这里插入图片描述

    1. 编辑和删除功能
      (1)按需引入 MessageBox 组件
      (2)main.js 中在 Vue 实例上拿到 MessageBox 下的 confirm 方法
      (3)main.js 中在 Vue 实例上拿到 Message
    	Vue.prototype.$confirm = MessageBox.confirm
    	Vue.prototype.$message = Message
    
    • 1
    • 2

    在 CommonTable.vue

    	<template slot-scope="scope">
          <!-- scope.row表示当前行的数据 -->
          <el-button size="mini" @click="handleEdit(scope.row)">编辑</el-button>
          <el-button size="mini" type="danger" @click="handleDelete(scope.row)">删除</el-button>
        </template>
    
    • 1
    • 2
    • 3
    • 4
    • 5

    效果图

    在这里插入图片描述

    在这里插入图片描述

    不积跬步无以至千里 不积小流无以成江海

    点个关注不迷路,持续更新中…

  • 相关阅读:
    【等保小课堂】等保测评后还要花很多钱做等保整改吗?
    DM@数理逻辑@命题公式及其赋值@真值表@公式分类
    k8s 部署 mongodb 三种模式
    0021Java程序设计-SSM框架图书管理系统
    卷积神经网络
    拖拽式在线表单设计器好用吗?
    Kafka3.0.0版本——消费者(消费者总体工作流程图解)
    K8s项目实战!阿里大佬带你深度解析Kubernetes
    如何评价2023年亚太杯数学建模竞赛?
    哪种护眼灯孩子用着最好?盘点五款用眼舒适度高的护眼灯
  • 原文地址:https://blog.csdn.net/qq_45902692/article/details/125328857