v-model绑定Object对象,保持单向数据流
vue中v-model绑定Object对象,如何保持组件的单向数据流
·
v-model做为vue中非常出色的语法糖,应该大家都对它用过了不少了,这里不在过多说明了,重点讲解一下v-model绑定的是一个对象在子组件怎么保持单项数据流,实现正确使用v-model。
常见写法
v-model绑定Object对象,在项目中见到很多人都是这样写,简单方便。就只是将单个换成Object类型就行了。
父组件
<template>
<div class="model_test">
<h2>父组件:{{ inputValue }}</h2>
<input-children v-model:value="inputValue"></input-children>
</div>
</template>
<script>
import inputChildren from './inputChildren.vue'
export default {
components: {
inputChildren
},
data() {
return {
inputValue: {
name: '',
region: 'shanghai',
delivery: false,
type: ''
}
}
}
}
</script>
<style lang="less" scoped>
.model_test {
margin-left: 50px;
display: flex;
flex-direction: column;
}
</style>
子组件
<template>
<div style="width: 200px">
<el-form label-position="top" label-width="80px" :model="value">
<el-form-item label="名称">
<el-input v-model="value.name"></el-input>
</el-form-item>
<el-form-item label="活动区域">
<el-select v-model="value.region" placeholder="活动区域">
<el-option label="上海" value="shanghai"></el-option>
<el-option label="北京" value="beijing"></el-option>
</el-select>
</el-form-item>
<el-form-item label="即时配送" prop="delivery">
<el-switch v-model="value.delivery"></el-switch>
</el-form-item>
<el-form-item label="活动形式">
<el-input v-model="value.type"></el-input>
</el-form-item>
</el-form>
</div>
</template>
<script>
export default {
props: {
value: {
type: Object,
default: ''
}
}
}
</script>
乍一看可以用,好像没什么问题,确实可以用。
破坏了vue单项数据流的原则,在子组件改变了父组件的数据。
每打破一次单向数据流,你的代码离屎山也就更进一步了。
保持单项数据流
v-model是个语法糖,这个基础知识了。
更新的时候我们可以用$emit('update:value',newValue)
这样就实现了父组件的数据更新
下面我列举了两种方式实现保持单项数据流的写法:
function
- 通过子组件再次通过双休数据绑定,将更新的update提取成公共方法,使用
$emit('update:value',newValue)
来实现父组件修改数据保持单项数据流。 - 比较不足的是子组件不能直接使用v-model语法糖
子组件改造
<template>
<div style="width: 200px">
<el-form label-position="top" label-width="80px" :model="value">
<el-form-item label="名称">
<el-input
:model-value="value.name"
@update:model-value="$event => handleUpdate('name', $event)">
</el-input>
</el-form-item>
<el-form-item label="活动区域">
<el-select
:model-value="value.region"
@update:model-value="$event => handleUpdate('region', $event)"
placeholder="活动区域">
<el-option label="上海" value="shanghai"></el-option>
<el-option label="北京" value="beijing"></el-option>
</el-select>
</el-form-item>
<el-form-item label="即时配送" prop="delivery">
<el-switch
:model-value="value.delivery"
@update:model-value="$event => handleUpdate('delivery', $event)">
</el-switch>
</el-form-item>
<el-form-item label="活动形式">
<el-input
:model-value="value.type"
@update:model-value="$event => handleUpdate('type', $event)">
</el-input>
</el-form-item>
</el-form>
</div>
</template>
<script>
const _that = {}
export default {
props: {
value: {
type: Object,
default: ''
}
},
methods: {
/**
* @description: 双向绑定的update更新函数
* @param {*} name 自定义更新的字段名
* @param {*} val 更新的内容
* @return {*}
*/
handleUpdate(name, val) {
this.$emit('update:value', {
...this.value,
[name]: val
})
}
}
}
</script>
computed and Proxy
- 利用computed自带的getter、setter方法
- Proxy实现改变computed监听到具体的setter方法
- 优势是不用二次绑定了,子组件可以直接采用v-model
不使用Proxy需要每个单独写一个计算属性,因为computed监听不到深层的变化(计算属性是对象,改变属性不能触发setter方法),所有配合着Proxy使用效果更佳。
子组件改造
<template>
<div style="width: 200px">
<el-form label-position="top" label-width="80px" :model="formData">
<el-form-item label="名称">
<el-input v-model="formData.name"></el-input>
</el-form-item>
<el-form-item label="活动区域">
<el-select v-model="formData.region" placeholder="活动区域">
<el-option label="上海" value="shanghai"></el-option>
<el-option label="北京" value="beijing"></el-option>
</el-select>
</el-form-item>
<el-form-item label="即时配送" prop="delivery">
<el-switch v-model="formData.delivery"></el-switch>
</el-form-item>
<el-form-item label="活动形式">
<el-input v-model="formData.type"></el-input>
</el-form-item>
</el-form>
</div>
</template>
<script>
export default {
props: {
value: {
type: Object,
default: ''
}
},
computed: {
formData: {
get() {
let _this = this
return new Proxy(this.value,{
set(obj,name,val) {
_this.$emit('update:value', {
...obj,
[name]: val
})
return true
}
})
}
}
}
}
</script>
优雅,写代码一定要优雅!
更多推荐
已为社区贡献2条内容
所有评论(0)