本文将通过一个具体的示例来介绍如何在 Vue 应用中实现一个带有表格和表单功能的弹窗组件。我们将使用 Element UI 库中的 el-dialog 组件来构建这个弹窗,并结合 el-table 和 el-form 来展示数据并允许用户进行编辑。
效果图:
完整代码最底部,以下拆分解析----------
1. 引入必要的 Element UI 组件
2. 创建弹窗结构
接下来定义弹窗的基本结构。这里我们使用 el-dialog 组件,并为其设置一些基本属性如标题、宽度等:
<el-dialog
class="edit-dialog"
title="编辑"
width="80%"
:center="true"
ref="dialogRef"
:visible.sync="dialogVisible"
@close="resetForm('resetForm')"
:before-close="beforeClose"
:close-on-click-modal="false"
:close-on-press-escape="false">
</el-dialog>
3. 添加表单和表格
在弹窗内部添加一个表单 (el-form) 和表格 (el-table),并通过 v-model 双向绑定数据
<el-form ref="formRef" style="padding: 20px" label-width="100px">
<el-table
border
stripe
class="table-style"
max-height="350"
:data="tableData"
style="width: 100%; min-height: 200px;">
<!-- 表格列定义 -->
</el-table>
</el-form>
4. 定义表格列
为表格定义多个列,包括索引、发票类型选择器、输入框等:
<el-table-column type="index" label="序号" align="center" width="60" show-overflow-tooltip></el-table-column>
<el-table-column prop="invoiceType" label="发票类型" align="center" min-width="280">
<template slot-scope="scope">
<el-select
multiple
style="width: 100%"
collapse-tags
v-model="scope.row.invoiceTypeCode">
<el-option
v-for="(item, index) in typeList"
:key="index"
:label="item.invoiceTypeName"
:value="item.invoiceTypeCode">
</el-option>
</el-select>
</template>
</el-table-column>
<el-table-column prop="taxCategory" label="税收分类简称" align="center" min-width="180">
<template slot-scope="scope">
<el-input placeholder="请输入税收分类简称" v-model="scope.row.taxCategory" clearable></el-input>
</template>
</el-table-column>
<el-table-column prop="taxRate" label="税率" align="center" min-width="180">
<template slot-scope="scope">
<el-input placeholder="请输入税率" v-model="scope.row.taxRate" clearable></el-input>
</template>
</el-table-column>
<el-table-column prop="dateRange" label="适用时间" align="center" min-width="280">
<template slot-scope="scope">
<el-date-picker
v-model="scope.row.dateRange"
type="daterange"
range-separator="至"
value-format="yyyy-MM-dd"
start-placeholder="开始日期"
end-placeholder="结束日期">
</el-date-picker>
</template>
</el-table-column>
<el-table-column label="操作" align="center" width="80" :render-header="renderHeader">
<template slot-scope="scope">
<i @click.prevent="deleteRow(scope.$index, scope.row)" class="el-icon-delete"></i>
</template>
</el-table-column>
5. 添加操作按钮
在弹窗底部添加两个按钮用于关闭和保存:
<div slot="footer">
<el-button size="medium" @click="closeDialog">取消</el-button>
<el-button size="medium" type="primary" ref="saveButton" @click="saveData('formRef')">保存</el-button>
</div>
6. 定义相关方法
最后,在 Vue 实例的方法部分定义与弹窗相关的处理逻辑,例如关闭时重置表单、保存数据等:
export default {
data() {
return {
dialogVisible: false,
tableData: [],
typeList: [], // 示例数据
formRef: null,
dialogRef: null
};
},
methods: {
resetForm(formName) {
this.$refs[formName].resetFields();
},
beforeClose(done) {
this.resetForm('formRef');
done();
},
deleteRow(index, row) {
this.tableData.splice(index, 1);
},
closeDialog() {
this.dialogVisible = false;
this.resetForm('formRef');
},
saveData(formName) {
this.$refs[formName].validate(valid => {
if (valid) {
// 保存数据逻辑
console.log(this.tableData);
this.closeDialog();
}
});
},
renderHeader(h, { column }) {
return h('span', [
h('i', { style: 'color: #409EFF' }, '添加行'),
h('span', '操作')
]);
}
}
};
完整代码如下:
<template>
<el-dialog
title="编辑"
width="80%"
:center="true"
ref="dialogRef"
:visible.sync="dialogVisible"
@close="resetForm('formRef')"
:before-close="beforeClose"
:close-on-click-modal="false"
:close-on-press-escape="false">
<el-form ref="formRef" style="padding: 20px" label-width="100px">
<el-table
border
stripe
class="custom-table"
max-height="350"
:data="tableData"
style="width: 100%; min-height: 200px;">
<el-table-column type="index" label="序号" align="center" width="60" show-overflow-tooltip></el-table-column>
<el-table-column prop="invoiceType" label="发票类型" align="center" min-width="280">
<template slot-scope="scope">
<el-select
multiple
style="width: 100%"
collapse-tags
v-model="scope.row.invoiceTypeCode">
<el-option
v-for="item in typeList"
:key="item.invoiceTypeCode"
:label="item.invoiceTypeName"
:value="item.invoiceTypeCode">
</el-option>
</el-select>
</template>
</el-table-column>
<el-table-column prop="taxCategory" label="税收分类简称" align="center" min-width="180">
<template slot-scope="scope">
<el-input
placeholder="请输入税收分类简称"
v-model="scope.row.taxCategory"
clearable>
</el-input>
</template>
</el-table-column>
<el-table-column prop="taxRate" label="税率" align="center" min-width="180">
<template slot-scope="scope">
<el-input
placeholder="请输入税率"
v-model="scope.row.taxRate"
clearable>
</el-input>
</template>
</el-table-column>
<el-table-column prop="dateRange" label="适用时间" align="center" min-width="280">
<template slot-scope="scope">
<el-date-picker
v-model="scope.row.dateRange"
type="daterange"
range-separator="至"
value-format="yyyy-MM-dd"
start-placeholder="开始日期"
end-placeholder="结束日期">
</el-date-picker>
</template>
</el-table-column>
<el-table-column label="操作" align="center" width="80" :render-header="renderHeader">
<template slot-scope="scope">
<i
@click.prevent="deleteRow(scope.$index, scope.row)"
class="el-icon-delete">
</i>
</template>
</el-table-column>
</el-table>
</el-form>
<div slot="footer">
<el-button size="medium" @click="closeDialog">取消</el-button>
<el-button size="medium" type="primary" ref="saveButton" @click="saveData('formRef')">保存</el-button>
</div>
</el-dialog>
</template>
<script>
export default {
data() {
return {
dialogVisible: false,
tableData: [
{
invoiceTypeCode: ['1'],
taxCategory: '',
taxRate: '',
dateRange: []
}
],
typeList: [
{ invoiceTypeCode: '1', invoiceTypeName: '增值税专用发票' },
{ invoiceTypeCode: '2', invoiceTypeName: '增值税普通发票' }
]
};
},
methods: {
resetForm(formName) {
this.$refs[formName].resetFields();
},
beforeClose(done) {
this.resetForm('formRef');
done();
},
deleteRow(index, row) {
this.tableData.splice(index, 1);
},
closeDialog() {
this.dialogVisible = false;
this.resetForm('formRef');
},
saveData(formName) {
this.$refs[formName].validate(valid => {
if (valid) {
console.log(this.tableData);
this.closeDialog();
}
});
},
addNewRule() {
this.tableData.push({
invoiceTypeCode: [],
taxCategory: '',
taxRate: '',
dateRange: [],
isDisabled: false
});
},
renderHeader(h, { column }) {
return h(
'div',
[
h('span', column.label),
h('i', {
class: 'el-icon-circle-plus',
style: 'color: #409eff; font-size: 24px; cursor: pointer;',
on: {
click: this.addNewRule
}
})
]
);
}
}
};
</script>
<style scoped>
.custom-dialog .el-dialog__body {
padding: 20px;
}
.custom-table {
margin-bottom: 20px;
}
.custom-table td, .custom-table .cell {
padding: 0px;
}
.custom-table .el-input__inner {
border-radius: 0;
}
.custom-table .el-icon-delete {
cursor: pointer;
}
.custom-dialog .el-dialog__header {
background: rgb(2, 65, 114);
color: #fff;
.el-dialog__title,
.el-icon {
color: #fff;
}
}
</style>