赞
踩
vue中父子组件通信,都是单项的,直接在子组件中修改prop传的值vue也会给出一个警告,接下来就用一个小列子一步一步实现了vue自定义的组件实现v-model双向绑定,需要的朋友可以参考下
项目中会遇到自定义公共组件供项目调用,正常情况可以使用 props定义参数接收父组件传的参数,然后通过子组件的$emits()方法回传数据给父组件。
类似如下:
<common-checkbox :checked="goodsSelected" class="left" `:height="'16px'" :width="'16px'" @checkChange="checkChange"></common-checkbox>
// 接收子组件回传进行处理
checkChange(value) {
this.goodsSelected=value//子组件数据赋值给父组件`
}
// 切换选中回传
toggleCheck(value) {
this.$emit('changeCheck', value) //回传方法,把子组件变化后的数据回传给父组件处理
}
但是这种写法需要调用公共组件的页面额外写处理的方法,而且显得太low,我们可不可以像是框架自带的公共组件一样去声明直接v-model双向绑定呢?接下来提供项目中实际遇到这种情况的处理方法
正常情况下当你在父组件里给子组件绑定 v-model属性时,子组件中会默认的将 v-model绑定的数据,付给子组件 名为 value的props属性,value依然需要提前在子组件props中声明,否则接收不到。
当 value修改后,并不会立即双向回传给父组件。如果想回传实现同步更新父组件的v-model需要如下操作
this.$emit('input', value)
当未声明双向绑定回传的事件时,默认通过input事件回传,为什么说 “当未声明双向绑定回传的事件”,这个便是第二种方式,下面会讲到。
简单来说,第一种方式的实现,首先是v-model绑定父组件数据 ,然后子组件value 的props属性自动接收,最后当数据更改后调用this.$emit(‘input’, value) 回传父组件,这样父组件不需要额外实现子组件的回传就可以实现双向绑定
组件
前面提到 “当未声明双向绑定回传的事件” 默认使用 input回传,既然这样说了那就存在,如果我不用input呢?这就需要了解vue的一个特殊的属性:model,这个属性可以用来声明 子组件用哪个字段去接收双向绑定的数据,以及用哪个方法回调更新父组件v-model的数据,写法如下:
export default {
name: 'CommonCkeckBox',
model: {
prop: 'checked',
event: 'changeCheck'
},
props: {
checked: {
type: Boolean,
default: false,
}, // 选中状态
}
}
这种写法就意味着,父组件 双向绑定的数据会绑定到子组件名为checked的props属性,并且,当子组件调用 this.$emit('changeCheck', value)
时,会同步的更新父组件的数据,实现双向绑定。
<template> <div class="check-box-container" @click="toggleCheck()" :style="{width:width,height:height}"> <div class="checkbox-icon"> <!-- 三种状态 选中 未选 禁用 --> <img alt :src="`${$cdnImageUrl}/cart/icon-selected.png`" :width="width" :height="height" key="select" v-if="checked&&!disabled"/> <img alt :src="`${$cdnImageUrl}/cart/icon-unselected.png`" :width="width" :height="height" key="unselected" v-if="!checked&&!disabled" /> <img alt :src="`${$cdnImageUrl}/cart/icon-unselected.png`" :width="width" :height="height" class="disabled" key="unselected" v-if="disabled"/> </div> <slot></slot> </div> </template> <script> /** * 全局统一弹窗 */ export default { name: 'CommonCkeckBox', model: { prop: 'checked', event: 'changeCheck' }, props: { checked: { type: Boolean, default: false, }, // 选中状态 disabled: { type: Boolean, default: false, }, // 是否禁用 width: { type: String, default: '16px', }, // 按钮默认宽度 height: { type: String, default: '16px', }, // 按钮默认高度 }, created() { }, data() { return { } }, methods: { /** * 切换选中回传 */ toggleCheck() { this.$emit('changeCheck', !this.checked) this.$emit('toggleCheck') } }, watch: { checked: { handler(newValue, oldValue) { // 开放状态变更事件 this.$emit('onChange') }, deep: true } }, } </script> <style lang="scss" scoped> .check-box-container{ display: inline-block; .checkbox-icon{ img{ transform: translateZ(0); will-change: auto; } .disabled{ background-color:#f5f5f5; border-radius: 50%; } } } </style>
父组件:
<common-checkbox v-model="item.goodsSelected" class="left" :width="'16px'" :height="'16px'"></common-checkbox>
具体用哪种方式根据项目场景选择,若第一种不满足需求,可以尝试第二种实现。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。