VueJS父子組件屬性同步
背景
為了解決ElementUI中Dialog+Form同時(shí)用于添加戴甩、修改操作時(shí)苛坚,F(xiàn)orm中輸入項(xiàng)值及檢驗(yàn)狀態(tài)滯留(顯示的是上一次關(guān)閉Dialog前的值)的問(wèn)題窒舟。
在父組件中對(duì)Table行數(shù)據(jù)進(jìn)行添加
怎憋、修改
操作姨丈,使用了ElementUI的Dialog組件屿衅,添加
埃难、修改
操作使用同一Dialog表單。那么問(wèn)題來(lái)了,點(diǎn)擊添加
按鈕時(shí)涡尘,對(duì)話框表單輸入項(xiàng)初始化狀態(tài)都應(yīng)置空忍弛;點(diǎn)擊修改
按鈕對(duì)話框表單輸入項(xiàng)應(yīng)初始化為當(dāng)前行的值;另外考抄,我給表單加了ElementUI自帶的輸入校驗(yàn)细疚。
Dialog關(guān)閉時(shí),僅設(shè)置了display:none
屬性川梅。每次Dialog顯示時(shí)都會(huì)遺留上一次關(guān)閉之前的值或者校驗(yàn)提示狀態(tài)疯兼。雖然可以在代碼中顯示重置表單各項(xiàng)數(shù)據(jù),以及通過(guò)this.$refs['form'].resetForm()
贫途、this.$refs['form'].clearValidate()
重置表單校驗(yàn)狀態(tài)吧彪,但是this.$refs['form'].resetForm()
重置后的表單值始終為第一次打開(kāi)Dialog時(shí)的值。
解決方案
我將Dialog+表單封裝為組件丢早。在父組件中引用子組件時(shí)添加v-if
姨裸,在關(guān)閉Dialog時(shí)將子組件銷毀。
核心代碼
<!-- 子組件Dialog關(guān)閉時(shí)向父組件發(fā)送事件 -->
<script>
this.$emit('update', this.isRender)
</script>
<!-- 父組件使用@update接受子組件事件香拉,并更新對(duì)話框顯示 -->
<menu-form-dialog v-if="dialogVisible" :render="dialogVisible" :form="form" :title="dialogTitle" @update="updateDialogVisible"/>
父組件
<template>
<div class="app-container">
<tree-table :data="data" :columns="columns" :expand-all="true" border>
<el-table-column :label="$t('app.common.opt')" width="250" align="center">
<template slot-scope="scope">
<el-button size="mini" type="success" @click="openAddDialog">{{ $t('app.common.add') }}</el-button>
<el-button size="mini" type="primary" @click="openEditDialog(scope.row)">{{ $t('app.common.edit') }}</el-button>
<el-button size="mini" type="danger">{{ $t('app.common.del') }}</el-button>
</template>
</el-table-column>
</tree-table>
<menu-form-dialog v-if="dialogVisible" :render="dialogVisible" :form="form" :title="dialogTitle" @update="updateDialogVisible"/>
</div>
</template>
<script>
import treeTable from '@/components/TreeTable'
import { getWebMenuList } from '@/api/sys/webmenu'
import menuFormDialog from './menu-form'
export default {
name: 'WebMenu',
components: { treeTable, menuFormDialog },
data() {
return {
dialogVisible: false,
dialogTitle: '',
form: {
parentId: '',
name: '',
href: '',
sort: 0,
isShow: '',
remarks: ''
},
columns: [
{
text: 'app.system.system.webmenu.name',
value: 'remarks',
width: 300
},
{
text: 'app.system.system.webmenu.i18nCode',
value: 'name'
},
{
text: 'app.system.system.webmenu.link',
value: 'href',
type: 'link'
},
{
text: 'app.system.system.webmenu.sort',
value: 'sort',
width: 100
},
{
text: 'app.system.system.webmenu.nodeType',
value: 'isShow',
width: 100,
formatter: this.nodeTypeFormatter
}
],
data: []
}
},
mounted() {
this.initTable()
},
methods: {
initTable() {
getWebMenuList().then(response => {
this.data = this.buildTreeData(response.data)
})
},
buildTreeData(list) {
console.time('buildTreeData')
const temp = {}
const tree = []
for (const i in list) {
temp[list[i].id] = list[i]
delete temp[list[i].id].parent
if (temp[list[i].id].parentId === 1) {
temp[list[i].id]['pid'] = temp[list[i].id].parentId
delete temp[list[i].id].parentId
}
}
for (const i in temp) {
if (temp[i].parentId) {
if (!temp[temp[i].parentId].children) {
temp[temp[i].parentId]['children'] = []
}
temp[temp[i].parentId].children.push(temp[i])
} else {
tree.push(temp[i])
}
}
this.sortTree(tree)
console.timeEnd('buildTreeData')
return tree
},
sortTree(tree) {
tree.sort((a, b) => a.sort - b.sort)
for (const i in tree) {
if (tree[i].children && tree[i].children.length > 0) {
this.sortTree(tree[i].children)
}
}
},
nodeTypeFormatter(value) {
let nodeType
value = parseInt(value)
switch (value) {
case 0:
nodeType = this.$t('app.system.system.webmenu.nodeTypeFunc')
break
case 1:
nodeType = this.$t('app.system.system.webmenu.nodeTypeMenu')
break
default:
nodeType = value
break
}
return nodeType
},
openAddDialog() {
this.form.parentId = ''
this.form.name = ''
this.form.href = ''
this.form.sort = 0
this.form.isShow = ''
this.form.remarks = ''
this.title = '添加'
this.dialogVisible = true
},
openEditDialog(row) {
this.form.parentId = row.parentId || row.pid
this.form.name = row.name
this.form.href = row.href
this.form.sort = row.sort
this.form.isShow = row.isShow
this.form.remarks = row.remarks
this.title = '編輯'
this.dialogVisible = true
},
updateDialogVisible(val) {
this.dialogVisible = val
}
}
}
</script>
子組件
<template>
<el-dialog v-el-drag-dialog :visible.sync="render" :title="title" :before-close="closeDialog" width="30%" @dragDialog="handleDrag">
<el-form ref="form" :model="form" :rules="rules" status-icon label-width="80px">
<el-form-item label="上級(jí)菜單" prop="parentId">
<el-input v-model="form.parentId" clearable/>
</el-form-item>
<el-form-item label="名稱" prop="name">
<el-input v-model="form.name" placeholder="請(qǐng)輸入i18n編碼" clearable/>
</el-form-item>
<el-form-item label="鏈接" prop="href">
<el-input v-model="form.href" placeholder="http://stock.jd.id" clearable/>
</el-form-item>
<el-form-item label="排序" prop="sort">
<el-input-number v-model="form.sort" :min="0" :max="1000"/>
</el-form-item>
<el-form-item label="節(jié)點(diǎn)類型" prop="isShow">
<el-radio-group v-model="form.isShow">
<el-radio label="0">功能點(diǎn)</el-radio>
<el-radio label="1">菜單</el-radio>
</el-radio-group>
</el-form-item>
<el-form-item label="備注" prop="remarks">
<el-input v-model="form.remarks" type="textarea" clearable/>
</el-form-item>
</el-form>
<span slot="footer" class="dialog-footer">
<el-button type="primary" @click="submitForm">保存</el-button>
<el-button @click="resetForm">重置</el-button>
</span>
</el-dialog>
</template>
<script>
import elDragDialog from '@/directive/el-dragDialog'
export default {
name: 'MenuFormDialog',
directives: { elDragDialog },
props: {
/* eslint-disable */
title: String,
form: Object,
render: {
type: Boolean,
default: false
}
},
data() {
const pattern = {
url: new RegExp('^(?!mailto:)(?:(?:http|https)://|//)(?:\\S+(?::\\S*)?@)?(?:(?:(?:[1-9]\\d?|1\\d\\d|2[01]\\d|22[0-3])(?:\\.(?:1?\\d{1,2}|2[0-4]\\d|25[0-5])){2}(?:\\.(?:[0-9]\\d?|1\\d\\d|2[0-4]\\d|25[0-4]))|(?:(?:[a-z\\u00a1-\\uffff0-9]+-?)*[a-z\\u00a1-\\uffff0-9]+)(?:\\.(?:[a-z\\u00a1-\\uffff0-9]+-?)*[a-z\\u00a1-\\uffff0-9]+)*(?:\\.(?:[a-z\\u00a1-\\uffff]{2,})))|localhost)(?::\\d{2,5})?(?:(/|\\?|#)[^\\s]*)?$', 'i')
}
const checkHref = (rule, value, callback) => {
if (typeof (value) === 'string' && !!value.match(pattern.url)) {
callback()
} else {
callback(new Error('請(qǐng)輸入http或https格式'))
}
}
return {
visible: this.render,
rules: {
parentId: [
{ required: true, message: '請(qǐng)選擇父級(jí)菜單', trigger: 'blur' }
],
name: [
{ required: true, message: '請(qǐng)輸入菜單i18n編碼', trigger: 'blur' }
],
href: [
{ required: true, message: '請(qǐng)輸入菜單鏈接', trigger: 'blur' },
{ validator: checkHref, trigger: 'blur' }
],
sort: [
{ required: true, message: '請(qǐng)輸入菜單排序', trigger: 'blur' }
],
isShow: [
{ required: true, message: '請(qǐng)選擇節(jié)點(diǎn)類型', trigger: 'change' }
],
remarks: [
{ required: true, message: '請(qǐng)輸入備注信息', trigger: 'blur' }
]
}
}
},
methods: {
handleDrag() {},
submitForm() {
this.$refs['form'].validate((valid) => {
if (valid) {
alert('submit!')
} else {
console.log('error submit!!')
return false
}
})
},
resetForm() {
this.$refs['form'].resetFields()
},
closeDialog(done) {
this.$refs['form'].clearValidate()
done()
this.$emit('update', this.isRender)
}
}
}
</script>