Vue2后台管理系统实现难点(2):

ElementUi组件库的编辑新增框Form组件的封装和table组件的封装:

1. form表单组件的封装:

image

  1. 首先通过elementUi组件库进行页面结构的搭建,(因为组件的复用(编辑弹出框和搜索框),所以封装一个commonForm组件), 其中值得我们注意的就是里面的model属性,这与下面table表格中的prop属性是差不多的,都是用于表单验证,指定表单的使用数据的!

commonForm组件(子组件)的封装代码如下:

<template>
<!-- 弹出框表单组件(点击添加,修改弹出的弹框) -->
<el-form ref="form" label-width="100px" :model="form" :inline="inline">
<!-- 遍历标题生成对应个数的表单 -->
<el-form-item v-for="item in formLabel" :key="item.label" :label="item.label">
<!-- 输入组件(item.model与table中的prop差不多,都是用于指定表单使用的数据的进行表单验证的) -->
<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>
<!-- 日期组件 -->
<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]"
>
<el-option
v-for="item in item.opts"
: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:Object,
// 单行显示
inline:Boolean
},
data() {
return {

}
},
}
</script>

2. table组件的封装

  1. 我们获取的用户数据是分页式的,一页20条用户数据,10页共两百条数据,因此要想在user组件当中通过用户数据(个数)的获取来遍历生成table表格最好还是通过组件的封装来实现。首先通过elementUi组件库封装一个commonTable组件,然后再user.vue中调用遍历生成分页式的用户table表格数据

  2. 这个commonTable组件里面的结构包含两大列,第一大列又分成5小列是用来显示用户的数据(姓名,年龄,性别,出生日期和地址),第二大列用于显示操作按钮(编辑和删除按钮)
    image

  3. 其中最难实现的便是table中的数据渲染,这里采取elementUitable表格里面的prop属性,这个属性的作用是:当el-table元素中注入data(就是这里的tableData)对象数组后,在el-table-column中用prop属性来对应对象中的键名即可填入数据,简单点说,prop属性就是指向你给table组件中传入的数据中的数组对象里面的某一个指定键名的属性里面属性值!(相当于指定table要用的数据)

    • elementUi中table表格数据的渲染流程
      image
    • 数据的转换实现流程(项目当中)
      image

commonTable组件(子组件)的封装代码如下:

<template>
<!-- 这里是遍历生成一条(行)的数据模板组件 -->
<div class="common-table">
<el-table :data="tableData" height="470px" stripe>
<!-- show-overflow-tooltip超长使用tooltip显示 -->
<el-table-column
show-overflow-tooltip
v-for="item in tableLabel"
:key="item.prop"
:label="item.label"
:width="item.width ? item.width : 125"
>
<!-- 通过slot-scope="scope"获取当前行的数据并显示 -->
<template slot-scope="scope">
<!-- 对象的属性读取方式:scope.row[item.prop] -->
<!-- 根据elementUI中的,当el-table元素中注入data对象数组后,
在el-table-column中用prop属性来对应对象中的键名即可填入数据, -->
<!-- 这里通过prop属性来指定对应的键名数据(tableData中)填入,如:name,age.... -->
<span style="margin-left:10px">{{scope.row[item.prop]}}</span>
</template>
</el-table-column>
<el-table-column label="操作" min-width="180">
<!-- 通过slot-scope="scope"获取当前行的数据并通过handleEdit()发送给User中的index[父组件] -->
<template slot-scope="scope">
<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>
<!-- 分页器 -->
<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来接收父组件(user.vue)传过来的数据
props:{
tableData: Array,
tableLabel: Array,
config: Object
},
methods: {
// 编辑
handleEdit(row){
// 向父组件抛出数据(事件总线)
// 将当前行的数据发送给User中的index[父组件]
this.$emit('edit', row)
},
// 删除
handleDelete(row){//(事件总线)
this.$emit('del', row)
},
// 分页器跳转函数
changePage(page){
this.$emit('changePage', page)
}
},
}
</script>

user组件(父组件)中调用上面两个组件代码:

<template>
<div class="manage">
<!-- 使用弹框组件包裹着form表单组件控制它的显示和隐藏 -->
<el-dialog
:title="operateType === 'add' ? '新增用户' : '更新用户'"
:visible.sync="isShow"
>
<!-- 这里的opertateForm和opertateFormLabel使用的都是双向数据绑定=>弹框变,页面变
将formLabel和form传过去给子组件进行数据的处理
-->
<common-form
:formLabel="opertateFormLabel"
:form="opertateForm"
:inline="true"
ref="form"
></common-form>
<div slot="footer" class="dialog-footer">
<el-button @click="isShow = false">取消</el-button>
<el-button type="primary" @click="confirm">确定</el-button>
</div>
</el-dialog>
<div class="manage-header">
<el-button type="primary" @click="addUser">+ 新增</el-button>
<!-- form表单的复用(搜索框表单) -->
<common-form
:formLabel="formLabel"
:form="searchForm"
:inline="true"
ref="form"
>
<!-- 搜索获取关键字(searchForm表单中的keyword) -->
<el-button type="primary" @click="getList(searchForm.keyword)">搜索</el-button>
</common-form>
</div>
<common-table
:tableData="tableData"
:tableLabel="tableLabel"
:config="config"
@changePage="getList()"
@edit="editUser"
@del="delUser"
></common-table>
</div>
</template>

<script>
// 引入Form组件 Table组件 api->getUser(获取mock中的用户数据)
import commonForm from '../../components/commonForm.vue'
import commonTable from '@/components/commonTable.vue'
import {getUser} from '../../../api/data'

export default {
name:'User',
components:{commonForm,commonTable},
data() {
return {
operateType:'add',
isShow:false,
// form弹框设置的信息
opertateFormLabel: [
{
model: 'name',
label: '姓名',
type: 'input'
},
{
model: 'age',
label: '年龄',
type: 'input'
},
{
model: 'sex',
label: '性别',
type: 'select',
opts: [
{
label: '男',
value: 1
},
{
label: '女',
value: 0
}
]
},
{
model: 'birth',
label: '出生日期',
type: 'date'
},
{
model: 'addr',
label: '地址',
type: 'input'
}
],
// form弹框输入信息
opertateForm:{
name:'',
addr:'',
age:'',
birth:'',
sex:''
},
// form搜索框设置的信息(搜索框的类型)
formLabel:[
{
model:"keyword",
label:'',
type:'input'
}
],
// form搜索框输入的信息(搜索关键字)
searchForm:{
keyword:''
},
// 用户的table显示数据
tableData:[],
// 用户的table显示数据标题
tableLabel:[
{
prop:"name",
label:"姓名",
},
{
prop:"age",
label:"年龄",
},
{
prop:"sexLabel",
label:"性别",
},
{
prop:"birth",
label:"出生日期",
width:200,
},
{
prop:"addr",
label:"地址",
width:320,
},
],
config:{
page:1,
total:30
}
}
},
methods: {
confirm(){//点击form弹框的确认按钮时首先判断是修改还是新增类型
// 点击更新用户
if(this.operateType === 'edit'){
// 编辑用户,将表单内的数据发送给mock(调用编辑接口 => updateUser接口)
this.$http.post('/user/edit',this.opertateForm).then(res=>{
console.log(res);
// 关闭form弹框
this.isShow = false
this.getList()
})
}else{
// 点击添加用户(调用新增接口 => createUser接口)
this.$http.post('/user/add',this.opertateForm).then(res=>{
console.log(res);
// 关闭form弹框
this.isShow = false
this.getList()
})
}
},
addUser(){//添加用户,form弹框表单的输入信息全部清空
// 显示form弹框
this.isShow = true
// 设置标识为add
this.operateType = 'add'
// form弹框数据初始化(添加就是清空表单里面的所有内容,让你输入)
this.opertateForm = {
name:'',
addr:'',
age:'',
birth:'',
sex:''
}
},
// 编辑用户
editUser(row){
this.operateType = 'edit'
this.isShow = true
// 编辑就是表单里面显示的内容就是你点击的那一行里面的数据
this.opertateForm = row
},
// 删除用户
delUser(row){
this.$confirm("此操作将永久删除该组件,是否继续?","提示" , {
confirmButtonText: "确认",
cancelButtonText: "取消",
type: "warning"
}).then(()=>{
const id = row.id
this.$http.post("/user/del",{
// 将该用户的id通过params参数拼接打乒url上发送给mock处理
params:{id}
}).then(()=>{
this.$message({
type:'success',
message:'删除成功!',
})
this.getList()
})
})
},
// 获取用户列表
getList(name = ''){
this.config.loading = true
name ? (this.config.page = 1) : ''
getUser({
page: this.config.page,
name
}).then(({data:res})=>{
console.log('获取到的用户数据',res);
this.tableData = res.list.map(item => {
// 因为性别的判别是返回的0和1,即女和男,故这里做一个判断赋值
item.sexLabel = item.sexLabel === 0 ? "女" : "男"
return item
})
this.config.total = res.count
this.config.loading = false
})
}
},
// 页面第一次创建首先获取用户数据
created() {
this.getList()
},
}
</script>

用户数据的增删改查请查看下一篇博客!