您的位置:首页 > Web前端 > Vue.js

Vue2 ,v-model,以及利用 v-model 实现组件props双向绑定的解决方案

2018-05-23 19:33 453 查看

一、v-model?

https://segmentfault.com/a/1190000009492595

 

v-model 其实是一个语法糖,这背后其实做了两个操作

  1. v-bind 绑定一个 value 属性

  2. v-on 指令给当前元素绑定 input 事件

在原生表单元素中

[code]<input v-model='something'>

就相当于

[code]<input v-bind:value="something" v-on:input="something = $event.target.value">

在自定义组件中

[code]<my-component v-model='something'></my-componment>

相当于

[code]<my-component v-bind:value='something' v-on:input='something = arguments[0]'></my-component>

这时候,something接受的值就是input是事件的回掉函数的第一个参数
所以在自定义的组件当中,要实现数据绑定,还需要使用[$emit]去触发input的事件。

[code]this.$emit('input', value)

二、利用 v-model 实现组件props双向绑定的解决方案?

https://segmentfault.com/a/1190000008662112

https://cn.vuejs.org/v2/guide/components.html#%E4%BD%BF%E7%94%A8%E4%BA%8B%E4%BB%B6%E6%8A%9B%E5%87%BA%E4%B8%80%E4%B8%AA%E5%80%BC

在项目中使用vue2来构建项目,跟 vue1 很大的一处不同在于2 取消了props 的双向绑定,改成只能从父级传到子级的单向数据流,初衷当然是好的,为了避免双向绑定在项目中容易造成的数据混乱。

解决方案一、

参考网上与github上,解决方案都是这样:

1、在父组件中,用data对象中创建一个props属性的副本

2、在子组件中,watch props属性,并赋予data副本,同步组件外对props的修改

3、在子组件中,watch data副本,emit一个方法,通知到组件外。

最常见的 modal为例子:

modal挺合适双向绑定的,外部可以控制组件的 显示或者隐藏,组件内部的关闭可以控制 visible属性隐藏,同时visible 属性同步传输到外部。

[code]///modal.vue  组件
<template>
<div class="modal" v-show="visible">
<div class="close" @click="cancel">X</div>
</div>
</template>

<script>
export default {
name:'modal',
props: {
value: {
type: Boolean,
default:false
}
},

data () {
return {
visible:false
}
},
watch:{
value(val) {
this.visible = val;
},
visible(val) {
this.$emit("visible-change",val);
}
},
methods:{
cancel(){
this.visible = false;
}
},
mounted() {
if (this.value) {
this.visible = true;
}
}
}
</script>

///调用modal组件
<modal :value="isShow" @visible-change="modalVisibleChange"></modal>

export default {
name: 'app',
data () {
return {
isShow:true,
}
},
methods:{
modalVisibleChange(val){
this.isShow = val;
}
}
}

这样就解决了 组件props 双向绑定的问题。 但是这样有一个不是太美观的现象就是 在父级调用 modal组件的时候,还需要写一个 modalVisibleChange 的methods. 总是显得这部分代码是多余的。 特别是写一个让别人用的公共组件,这样调用太麻烦了。

能不能不写method来实现props的双向绑定呢,答案是可以的。

 

优美解决方案、

那就是利用 v-model, 然后使用value来保存v-model的值,进行双向绑定

[code]<template>
<div class="modal" :value="value" v-show="visible">
<div class="close" @click="cancel">X</div>
</div>
</template>

<script>
export default {
props: {
value: {
type: Boolean,
default:false
}
},

data () {
return {
visible:false
}
},
watch:{
value(val) {
this.visible = val;
},
visible(val) {
this.$emit('input', val);
}
},
methods:{
cancel(){
this.visible = false;
}
},
mounted() {
if (this.value) {
this.visible = true;
}
}
}
</script>

///调用modal组件

<modal v-model="isShow"></modal>

export default {
name: 'app',
data () {
return {
isShow:false
}
}
}
</script>

只要设置 isShow 就可以控制 modal 组件的显示或者隐藏,同时 如果是modal 组件内部关闭按钮关闭的,状态也会传到 isShow。

实例:实现公共组件

[code]<template>
<transition name="fade">
<div v-show="visible">
<div v-if="showModal"></div>
<div @click="handleWrapClick">
<div>
<div>
<slot name="tips"></slot>
<div @click="close" v-if="showClose">
<img src="../../assets/images/intent/close.png">
</div>
</div>
<slot name="footer"></slot>
</div>
</div>
</div>
</transition>
</template>
<script>
export default {
    name: 'confirm',
    props: {
showModal: {
        type: Boolean,
        default: false
},
showClose: {
        type: Boolean,
        default: false
        },
value: {
 type: Boolean,
default: false
},
closable: {
 type: Boolean,
default: true
},
maskClosable: {
 type: Boolean,
default: false
},
authClose: {
        type: Boolean,
        default: true
},
model: {
        type: String,
        default: ''
}
    },
data(){
return {
visible: this.value,
timer: null
}
},
watch: {
value(val){
 this.visible = val
},
visible(val){
if(val === false){
if(this.timer){
clearTimeout(this.timer)
}
return
}
if(this.authClose){
this.timer = setTimeout(() => {
this.close()
}, 2500)
}
}
},
methods: {
close(){
this.visible = false
if(this.model){
this.$parent[this.model] = false
}
            },
            mask(){
            if(this.maskClosable){
                 this.close()
             }
},
handleWrapClick(event){
if(event.target == event.currentTarget){
this.mask()
}
}
}
}
[code]<confirm v-model="showConfirm" model="showConfirm" maskClosable showModal :showClose="showClose" :authClose="authClose">
<div slot="tips">
<div :class="confirmImgClass"></div>
<div v-html="confirmTips"></div>
</div>
<div slot="footer" v-if="confirmBtnList && confirmBtnList.length">
<div v-for="btn in confirmBtnList" :key="btn.btnText" @click="btn.btnCallBack" :class="{active: btn.active}">{{btn.btnText}}</div>
</div>
</confirm>

data () {
return {
flag: true,
showOptTips: false,
optTips: '',
showConfirm: false,
showClose: false,
authClose: false,
confirmTips: '备注仅能添加一次,请确定已经完善内容。',
confirmImgClass: 'confirm-yellow-warning',
confirmBtnList: []
}
},

submit() {
this.confirmBtnList = [
{
btnText: '提交',
btnClass: '',
active: false,
btnCallBack: () => {
this.showConfirm = false;
this.isSubmit (true)
}
},
{
btnText: '取消',
btnClass: '',
btnCallBack: () => {
this.showConfirm = false;
this.isSubmit (false)
}
}
]

if (this.flag) {
this.showConfirm = true;
} else {
this.showConfirm = false;
}
},
isSubmit (msg) {
if (msg) {
this.flag = false;
//处理部分
} else {
this.flag = true;
//处理部分
}

 

 

 

阅读更多
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐