应用场景:子组件数据发送改变时父组件也做出相应的改变
方法一:通过v-model实现
适用范围:数据简单的情况
思路:父组件通过v-model绑定,子组件通过 prop接收modelValue,然后通过监听该数据,再分发出去,从而实现父子组件的双向绑定。
注意:拿到modelValue不能直接修改,否则会报警告。
原因:直接修改,违背了vue的单向数据流原则,也就是父组件传过来的值在子组件中不能直接修改。
解决方法:定义个变量将modelValue做个浅拷贝保存起来,修改这个变量。
父组件
<template>
<div>
<son v-model="fatherData"></son>
father数据展示 <br/>
姓名:{{ fatherData.name }}
年龄:{{ fatherData.age }}
性别:{{ fatherData.sex }}
</div>
</template>
<script lang="ts">
import { defineComponent } from 'vue'
import Son from './son.vue'
export default defineComponent({
components: {
Son
},
setup() {
let fatherData = {
name: '小明',
age: 18,
sex: '男'
}
return { fatherData }
}
})
</script>
<style scoped></style>
子组件
<template>
<div>
姓名:<input type="text" v-model="sonData.name" /><br />
年龄:<input type="number" v-model="sonData.age" /><br />
性别:<input type="text" v-model="sonData.sex" />
</div>
</template>
<script lang="ts">
import { defineComponent, watch, ref } from 'vue'
export default defineComponent({
props: {
modelValue: {
type: Object,
required: true
}
},
emits: ['update:modelValue'],
setup(props, { emit }) {
const sonData = ref({ ...props.modelValue })
watch(
() => sonData,
(newValue) => {
console.log(newValue)
emit('update:modelValue', newValue.value)
},
{ deep: true }
)
return { sonData }
}
})
</script>
<style scoped></style>
方式二:通过v-bind和v-on实现
这个方法和v-model本质上是一样的,因为v-model (:value+@input) 只是一中语法糖写法,拆开还是v-model和v-on
使用范围:数据及传值过程复杂或者对其数据进行其他操作时(也就是说父组件的值来自它的父组件甚至来自他的父父组件),这时使用v-model,就会出现数据丢失,没实现双向的情况。
思路:父组件依然可通过v-model(如果需要有额外的操作,父组件也需要通过v-bind和v-on绑定)来绑定值,但子组件就通过v-bind和v-on绑定。
父组件
<el-input
v-bind="item.otherOptions"
:model-value="modelValue[`${item.field}`]"
@update:modelValue="handleValueChange($event, item.field)"
></el-input>
子组件
<template>
<div>
姓名:<el-input
type="text"
:modelValue="sonData.name"
@update:modelValue="handleValueChange($event, 'name')"
></el-input>
{{ modelValue.name }}
<br />
年龄:<input
type="text"
:value="sonData.age"
@input="handleValueChanges($event, 'age')"
/><br />
{{ modelValue.age }}
性别:<input
type="text"
:value="sonData.sex"
@input="handleValueChanges($event, 'sex')"
/>
</div>
</template>
<script lang="ts">
import { defineComponent, watch, ref } from 'vue'
export default defineComponent({
props: {
modelValue: {
type: Object,
required: true
}
},
emits: ['update:modelValue'],
setup(props, { emit }) {
console.log('props', props.modelValue)
const sonData = ref<any>({ ...props.modelValue })
const handleValueChange = (value: any, field: string) => {
sonData.value[field] = value
emit('update:modelValue', { ...sonData.value, [field]: value })
}
const handleValueChanges = (e: any, field: string) => {
sonData.value[field] = e.target.value
emit('update:modelValue', { ...sonData.value, [field]: e.target.value })
}
return { handleValueChange, handleValueChanges, sonData }
}
})
</script>
<style scoped></style>