一、问题描述
最近学习过程中遇到这样一个问题。我想实现点击表格的每一行的修改按钮,都弹出一个modal框。
最初的思路(注意:之前用element-ui这么做没问题
),封装一个modal组件,然后在父组件进行引入,当点击修改按钮的时候,改变显示与否的状态,并且传给modal子组件,子组件通过props接收。
但问题来了,点击第一次,可以正常弹出并且关闭,点击第二次modal框不弹了,并且始终报错
[Vue warn]: Avoid mutating a prop directly since the value will be overwritten whenever the parent component re-renders. Instead, use a data or computed property based on the prop’s value. Prop being mutated: “visible”
看一个大概示例
父组件
<template>
<div>
<a-table
:columns="columns"
:data-source="userData"
bordered
rowKey="_id"
size="small"
:pagination="false"
>
<span slot="roleTags" slot-scope="roleTags">
<a-tag color="blue">{
{
roleTags}}</a-tag>
</span>
<span slot="jobTags" slot-scope="jobTags">
<a-tag color="green">{
{
jobTags}}</a-tag>
</span>
<span slot="action" slot-scope="userInfo">
<a-button type="link" @click="showUpdateModal">修改</a-button>
<a-divider type="vertical" />
<a-popconfirm
title="确定删除?"
ok-text="是"
cancel-text="否"
@confirm="sureDelete(userInfo)"
@cancel="cancelDelete"
>
<a>删除</a>
</a-popconfirm>
</span>
</a-table>
<div class="pagination">
<a-pagination
size="small"
:total="this.total"
show-size-changer
show-quick-jumper
:defaultPageSize="this.pageSize"
:pageSizeOptions="['2','5','10','15']"
:show-total="total => `共${this.total}条`"
@change="currentSizeData"
@showSizeChange="changeSize"
/>
</div>
<UpdateUser :updateUserModal="updateUserModal" />
</div>
</template>
<script>
import {
getAllUser, getRoleId, deleteUser } from '@/network/user.js'
import {
formateDate } from '@/utils/dateUtils.js'
import UpdateUser from './UpdateUser'
const columns = [
{
title: '用户名',
dataIndex: 'username',
align: 'center',
},
{
title: '邮箱',
dataIndex: 'email',
align: 'center',
},
{
title: '联系方式',
dataIndex: 'phone',
align: 'center',
},
{
title: '所属角色',
align: 'center',
dataIndex: 'roleName',
scopedSlots: {
customRender: 'roleTags' },
},
{
title: '职称',
align: 'center',
dataIndex: 'job',
scopedSlots: {
customRender: 'jobTags' },
},
{
title: '注册时间',
dataIndex: 'create_time',
align: 'center',
customRender: formateDate
},
{
title: '操作',
align: 'center',
scopedSlots: {
customRender: 'action' },
},
];
export default {
name: 'userManager',
data () {
return {
userData: [],
columns,
pageNum: 1,
pageSize: 5,
total: 0,
updateUserModal: false, //更新用户的modal
};
},
components: {
UpdateUser
},
computed: {
},
mounted () {
this.getAllUser(this.pageNum, this.pageSize)
},
methods: {
//获取所有用户列表
async getAllUser (pageNum, pageSize) {
const usersInfos = await getAllUser(pageNum, pageSize)
console.log(usersInfos)
if (usersInfos.status == 200) {
this.total = usersInfos.data.data.total
for (let item of usersInfos.data.data.list) {
const curRoleId = item.role_id
//有的用户还没有角色,防止因为传空值给后端接口造成问题
if (curRoleId != '') {
//根据roleid获取角色名称
const curRoleName = await getRoleId(curRoleId)
item.roleName = curRoleName.data.data
}
}
this.userData = usersInfos.data.data.list
}
},
//删除一个用户
sureDelete (userInfo) {
console.log(userInfo)
deleteUser(userInfo._id).then(res => {
if (res.data.status === 200) {
this.$message.success(res.data.msg)
//删除用户之后重新获取所有用户
this.getAllUser(this.pageNum, this.pageSize)
}
})
},
//取消删除
cancelDelete () {
this.$message.success('取消删除成功')
},
//点击页码重新发起请求
currentSizeData (currentPage, pageSize) {
this.getAllUser(currentPage, this.pageSize)
},
//改变页码时,重新获取数据
changeSize (current, size) {
this.pageSize = size
this.getAllUser(current, this.pageSize)
},
//显示更新用户的modal
showUpdateModal () {
console.log('*********')
this.updateUserModal = true
}
},
};
</script>
<style scoped>
/* 分页位置 */
.pagination {
margin-top: 15px;
float: right;
}
</style>
子组件
<template>
<div class="updateModal">
<a-modal
:visible="updateUserModalStatu"
title="更新用户信息"
@cancel="cancel"
:destroyOnClose="destory"
>
<p>Some contents...</p>
<p>Some contents...</p>
<p>Some contents...</p>
</a-modal>
</div>
</template>
<script>
export default {
name: '',
props: {
updateUserModal: {
type: Boolean,
default: () => {
return false
}
}
},
data () {
return {
destory: true,
updateUserModalStatu: this.updateUserModal,
};
},
watch: {
updateUserModal (value) {
console.log(value)
this.updateUserModalStatu = value
}
},
computed: {
},
methods: {
cancel () {
console.log('****')
this.updateUserModalStatu = false
}
},
components: {
},
};
</script>
<style scoped>
</style>
二、解决办法
利用vue $refs实现
不通过传值和props接收传值的方式了,通过使用ref直接操作子组件,控制其显示与否
父组件
<template>
<div>
<a-table
:columns="columns"
:data-source="userData"
bordered
rowKey="_id"
size="small"
:pagination="false"
>
<span slot="roleTags" slot-scope="roleTags">
<a-tag color="blue">{
{
roleTags}}</a-tag>
</span>
<span slot="jobTags" slot-scope="jobTags">
<a-tag color="green">{
{
jobTags}}</a-tag>
</span>
<span slot="action" slot-scope="userInfo">
<a-button type="link" @click="showUpdateModal">修改</a-button>
<a-divider type="vertical" />
<a-popconfirm
title="确定删除?"
ok-text="是"
cancel-text="否"
@confirm="sureDelete(userInfo)"
@cancel="cancelDelete"
>
<a>删除</a>
</a-popconfirm>
</span>
</a-table>
<div class="pagination">
<a-pagination
size="small"
:total="this.total"
show-size-changer
show-quick-jumper
:defaultPageSize="this.pageSize"
:pageSizeOptions="['2','5','10','15']"
:show-total="total => `共${this.total}条`"
@change="currentSizeData"
@showSizeChange="changeSize"
/>
</div>
<UpdateUser ref="modal" />
</div>
</template>
<script>
import {
getAllUser, getRoleId, deleteUser } from '@/network/user.js'
import {
formateDate } from '@/utils/dateUtils.js'
import UpdateUser from './UpdateUser'
const columns = [
{
title: '用户名',
dataIndex: 'username',
align: 'center',
},
{
title: '邮箱',
dataIndex: 'email',
align: 'center',
},
{
title: '联系方式',
dataIndex: 'phone',
align: 'center',
},
{
title: '所属角色',
align: 'center',
dataIndex: 'roleName',
scopedSlots: {
customRender: 'roleTags' },
},
{
title: '职称',
align: 'center',
dataIndex: 'job',
scopedSlots: {
customRender: 'jobTags' },
},
{
title: '注册时间',
dataIndex: 'create_time',
align: 'center',
customRender: formateDate
},
{
title: '操作',
align: 'center',
scopedSlots: {
customRender: 'action' },
},
];
export default {
name: 'userManager',
data () {
return {
userData: [],
columns,
pageNum: 1,
pageSize: 5,
total: 0,
updateUserModal: false, //更新用户的modal
};
},
components: {
UpdateUser
},
computed: {
},
mounted () {
this.getAllUser(this.pageNum, this.pageSize)
},
methods: {
//获取所有用户列表
async getAllUser (pageNum, pageSize) {
const usersInfos = await getAllUser(pageNum, pageSize)
console.log(usersInfos)
if (usersInfos.status == 200) {
this.total = usersInfos.data.data.total
for (let item of usersInfos.data.data.list) {
const curRoleId = item.role_id
//有的用户还没有角色,防止因为传空值给后端接口造成问题
if (curRoleId != '') {
//根据roleid获取角色名称
const curRoleName = await getRoleId(curRoleId)
item.roleName = curRoleName.data.data
}
}
this.userData = usersInfos.data.data.list
}
},
//删除一个用户
sureDelete (userInfo) {
console.log(userInfo)
deleteUser(userInfo._id).then(res => {
if (res.data.status === 200) {
this.$message.success(res.data.msg)
//删除用户之后重新获取所有用户
this.getAllUser(this.pageNum, this.pageSize)
}
})
},
//取消删除
cancelDelete () {
this.$message.success('取消删除成功')
},
//点击页码重新发起请求
currentSizeData (currentPage, pageSize) {
this.getAllUser(currentPage, this.pageSize)
},
//改变页码时,重新获取数据
changeSize (current, size) {
this.pageSize = size
this.getAllUser(current, this.pageSize)
},
//显示更新用户的modal
showUpdateModal () {
this.$refs.modal.show()
}
},
};
</script>
<style scoped>
/* 分页位置 */
.pagination {
margin-top: 15px;
float: right;
}
</style>
子组件
<template>
<div class="updateModal">
<a-modal :visible="updateUserModal" title="更新用户信息" @cancel="cancel">
<p>Some contents...</p>
<p>Some contents...</p>
<p>Some contents...</p>
</a-modal>
</div>
</template>
<script>
export default {
name: '',
// props: {
// updateUserModal: {
// type: Boolean,
// default: () => {
// return false
// }
// }
// },
data () {
return {
updateUserModal: false,
};
},
computed: {
},
methods: {
cancel () {
this.updateUserModal = false
},
show () {
this.updateUserModal = true
}
},
components: {
},
};
</script>
<style scoped>
</style>