在实际应用中,往往需要一个报表列表页,支持表单数据的添加或修改,操作完毕后关闭子页并刷新列表页面,效果如下图
主页面关键代码:
1)在主页面引入待弹出modal页的组件
<productEditModal :show="{'showModal': showModal, 'productId': productId}" @on-close="closeModal" ></productEditModal>
<script> import productEditModal from '@/content/productEdit'// 引入子页面 export default { components: { productEditModal }, ... </script>
2)在主页面中定义弹窗和关闭弹出的函数,其中,showModal、productId为定义的变量,将会传入弹出子页,分别代表是否弹出页和传入到子页面主键值
methods: { // 关闭弹框,赋值父页面。isRefresh用于标识是否刷新父页面(子页面内容有变化时传入true值) closeModal (resVal) { console.log('子组件传来的值:' + resVal) this.showModal = resVal.isClose if (resVal.isRefresh) { this.getList() } }, // 弹出页面 openModal (index) { console.log('序列号:' + index) this.showModal = true this.productId = 0// 默认新增0 index > -1 && (this.productId = this.tbData[index].id) }, ... }
子页面关键代码:
1)定义modal页面内容
<template> <Modal v-model="showModal" title="产品编辑" width="800" :footer-hide=true :closable="false" > <!--此处放置表单中的控件--> </Modal> </template>
2)子页面在watch中接收父页面传来值并调用子页数据加载方法
export default { // 父组件传来的值 props: ['show', 'productId'], data () { // 这里存放数据 return { showModal: false, curProduct: { id: 0, name: '', code: '', remark: '' }// 当前页面的产品信息 } }, // 监听属性 类似于data概念 computed: {}, // 方法集合 methods: { // 关闭子页面 onCancel (isRefresh) { this.showModal = false this.curProduct = { id: 0, name: '', code: '', remark: '' }// 初始化 this.$emit('on-close', { isclose: true, isRefresh: isRefresh }) }, ... init(productId){//缺省} }, // 获取父页面传来的值,并根据主键id请求数据 watch: { show (validate) { console.log(validate) if (validate.showModal === true) { this.showModal = validate.showModal if (validate.productId > 0) { this.init(validate.productId) } else { this.curProduct = { id: 0, name: '', code: '', remark: '' }// 初始化 } } } }
3)子页面重写保存和关闭按钮,隐藏modal的底部按钮区(:footer-hide=true),自行控制弹出页面的开关,请查看子页完整代码。
主页完整代码如下:
<template> <div class="main-content"> <Row type="flex"> <i-col span="2" class="main-lable" > 产品名称: </i-col> <i-col span="6"> <i-input placeholder="请输入产品名称" style=" 200px" v-model="proName" ></i-input> </i-col> <i-col span="8"> <Button type="info" icon="ios-search" @click="getList" >查询</Button> <Button icon="ios-add" type="success" @click="openModal(-1)" >新增</Button> </i-col> </Row> <div style="margin-top:10px"> <Table border :columns="tbColumns" :data="tbData" > <template slot-scope="{ row, index }" slot="action" > <Button type="error" size="small" style="margin-right: 5px" @click="deleteRow(index)" >删除</Button> <Button type="info" size="small" style="margin-right: 5px" @click="openModal(index)" >编辑</Button> </template> </Table> </div> <div class="main-page"> <Page :total="totals" :page-size="pageSize" @on-change="change" show-elevator ></Page> </div> <productEditModal :show="{'showModal': showModal, 'productId': productId}" @on-close="closeModal" ></productEditModal> </div> </template> <script> import productEditModal from '@/content/productEdit'// 数据源列表 export default { data () { return { self: this, proName: '', // 产品名称(过滤项) totals: 0, // 数据行数 pageSize: 10, // 每页显示条数 pageIndex: 1, // 当前页 tbColumns: [ { title: '编号', 80, key: 'id' }, { title: '产品名称', 150, key: 'name' }, { title: '产品代码', 100, key: 'code' }, { title: '产品描述', key: 'remark' }, { title: '操作', slot: 'action', 200, align: 'center' } ], tbData: [], showModal: false, // 是否显示子组件 productId: 0// 传给子组件的主键id } }, components: { productEditModal }, methods: { // 关闭弹框,赋值父页面 closeModal (resVal) { console.log('子组件传来的值:' + resVal) this.showModal = resVal.isClose if (resVal.isRefresh) { this.getList() } }, // 弹出页面 openModal (index) { console.log('序列号:' + index) this.showModal = true this.productId = 0// 默认新增0 index > -1 && (this.productId = this.tbData[index].id) }, // 删除一条数据 deleteRow (index) { var that = this let proId = this.tbData[index].id if (proId > 0) { this.$Modal.confirm({ title: '提示', content: '确认要删除名称为[' + this.tbData[index].name + ']的产品吗?', onOk: () => { this.$axios .delete('/api/v1/product/' + proId) .then(response => { console.log(response) debugger if (response.data.isError) { console.log(response) this.$Modal.error({ title: '提示', content: '删除失败!', onOk: () => { // this.$Message.info('Clicked ok') }, onCancel: () => { // this.$Message.info('Clicked cancel') } }) // this.$Message.error('新增失败:' + response.data.message) } else { this.$Modal.success({ title: '提示', content: '删除成功!', onOk: () => { // this.$Message.info('Clicked ok') // this.onCancel(true) debugger that.getList() }, onCancel: () => { // this.$Message.info('Clicked cancel') } }) } }) .catch(function (error) { // 请求失败处理 console.log(error) }) }, onCancel: () => { this.$Message.info('您已取消删除.') } }) } }, // 加载表格内容(含过滤、分页) getList () { // 拼装请求数据 let filter = {} this.proName && (filter.name = { like: this.proName }) this.$axios .post('/api/v1/product/list', { filter: filter, sort: { id: 'ASC', name: 'DESC' }, page: this.pageIndex, limit: this.pageSize }) .then(response => { console.log(response) this.tbData = response.data.data.docs this.totals = response.data.data.totals // console.log(this.totals) }) .catch(function (error) { // 请求失败处理 console.log(error) }) }, // 分页改变时 change (page) { // console.log(page) this.pageIndex = page this.getList() } }, // 生命周期 - 挂载完成,template模板挂在到组件上(可以访问DOM元素) mounted () { this.getList() } } </script> <!-- Add "scoped" attribute to limit CSS to this component only --> <style scoped> .main-content { height: 100%; } .main-lable { line-height: 30px; text-align: right; } .main-page { 100%; position: absolute; bottom: 2px; text-align: center; } </style>
子页完整代码如下:productEdit.vue
<template> <Modal v-model="showModal" title="产品编辑" width="800" :footer-hide=true :closable="false" > <i-form :label-width="100"> <div class="ivu-card ivu-card-dis-hover"> <div class="ivu-card-body" style="verflow-y:auto;overflow-x: hidden;" > <div class="ivu-row" style="margin-left: -12px; margin-right: -12px;" > <Row type="flex"> <i-col span="12"> <Form-item label="产品名称:" prop="name" > <i-input v-model="curProduct.name" placeholder="请输入产品名称" style="80%" ></i-input> </Form-item> </i-col> <i-col span="12"> <Form-item label="产品代码:" prop="code" > <i-input v-model="curProduct.code" placeholder="请输入产品代码" style="80%" ></i-input> </Form-item> </i-col> </Row> <Row type="flex"> <i-col span="24"> <Form-item label="数据源描述:"> <Input type="textarea" :rows="4" placeholder="请输入数据源描述" v-model="curProduct.remark" style="91%" /> </Form-item> </i-col> </Row> <div style="text-align: right;margin-top: 10px;"> <!-- <Button @click="onCancel()">取消</Button> --> <button type="button" class="ivu-btn ivu-btn-primary" @click="onSave" > <span>提交</span> </button> <button type="button" class="ivu-ml ivu-btn ivu-btn-default" @click="onCancel(false)" > <span>取消</span> </button> </div> </div> </div> </div> </i-form> </Modal> </template> <script> // 这里可以导入其他文件(比如:组件,工具js,第三方插件js,json文件,图片文件等等) // 例如:import 《组件名称》 from '《组件路径》'; export default { // 父组件传来的值 props: ['show', 'productId'], data () { // 这里存放数据 return { showModal: false, curProduct: { id: 0, name: '', code: '', remark: '' }// 当前页面的产品信息 } }, // 监听属性 类似于data概念 computed: {}, // 方法集合 methods: { // 关闭子页面 onCancel (isRefresh) { this.showModal = false this.curProduct = { id: 0, name: '', code: '', remark: '' }// 初始化 this.$emit('on-close', { isclose: true, isRefresh: isRefresh }) }, // 保存产品信息 onSave () { console.log(this.isNew) if (this.curProduct.id > 0) { this.$axios .put('/api/v1/product', { entity: this.curProduct }) .then(response => { if (response.data.isError) { this.$Modal.error({ title: '提示', content: '修改失败', onOk: () => { // this.$Message.info('Clicked ok') }, onCancel: () => { // this.$Message.info('Clicked cancel') } }) } else { this.$Modal.success({ title: '提示', content: '修改成功!', onOk: () => { this.onCancel(true) // this.$Message.info('Clicked ok') }, onCancel: () => { // this.$Message.info('Clicked cancel') } }) } }) .catch(function (error) { // 请求失败处理 console.log(error) }) } else { this.$axios .post('/api/v1/product', { entity: this.curProduct }) .then(response => { if (response.data.isError) { console.log(response) this.$Modal.error({ title: '提示', content: '保存失败', onOk: () => { // this.$Message.info('Clicked ok') }, onCancel: () => { // this.$Message.info('Clicked cancel') } }) // this.$Message.error('新增失败:' + response.data.message) } else { this.$Modal.success({ title: '提示', content: '保存成功!', onOk: () => { // this.$Message.info('Clicked ok') this.onCancel(true) }, onCancel: () => { // this.$Message.info('Clicked cancel') } }) } }) .catch(function (error) { // 请求失败处理 console.log(error) }) } }, init: function (proId) { // 初始化页面内容 console.log('子页初始化:' + proId) // 编辑时 if (proId > 0) { // 根据proId获得数据源信息,并加载到页面上 this.$axios .get('/api/v1/product/' + proId) .then(response => { // console.log(response); (response.data.data) && (this.curProduct = response.data.data) console.log(this.curProduct) }) .catch(function (error) { // 请求失败处理 console.log(error) }) } } }, // 获取父页面传来的值,并根据主键id请求数据 watch: { show (validate) { console.log(validate) if (validate.showModal === true) { this.showModal = validate.showModal if (validate.productId > 0) { this.init(validate.productId) } else { this.curProduct = { id: 0, name: '', code: '', remark: '' }// 初始化 } } } } } </script>