前言

我们在vue项目中,经常有这样的需求,父组件绑定v-model,子组件输入更改父组件v-model绑定的数值。很多朋友对这种操作不是很清楚,这需要对v-model有比较深入的了解,今天谈谈v-model。

vue的双向数据绑定

这个问题在很多前端面试中,会提及。面试官问你,vue的双向数据绑定原理是什么?当然,这个也是耳熟能详的问题,百度随便一搜索,到处都能找到答案。

一般都会搜索到,是用Object.defineProperty( ),来监听数据get和set,来实现数据劫持的。

假如对Object.defineProperty( )不是很了解,可以点击上面链接,看看其语法!

举个简单的例子:

var blog = {
  name: 'whyhome'
};
console.log(blog.name);  // whyhome

如果想要在执行console.log(blog.name)的同时,直接给whyhome博客加个书名号,那要怎么处理呢?或者说要通过什么监听对象 blog的属性值。这时候Object.defineProperty( )就派上用场了,代码如下:

var blog= {}
var name = '';
Object.defineProperty(blog, 'name', {
  set: function (value) {
    name = value;
    console.log('欢迎来到' + value);
  },
  get: function () {
    return '《' + name + '》'
  }
})

blog.name = 'whyhome';  // 欢迎来到whyhome
console.log(blog.name);  // 《whyhome》

上面代码执行一下,可以查看效果!

关于 vue的双向数据绑定,具体如何实现的?网上也有很多实现的代码,这里就不多累赘了!

v-model 的使用

上面开了一个小差,讲了那么多,其实就是为了说明Vue 是单项数据流,v-model 只是语法糖而已。

语法糖

<input v-model="whyrooms" />

解析

<input v-bind:value="whyrooms" v-on:input="whyrooms= $event.target.value" />

简写

<input :value="whyrooms"  @input="whyrooms= $event.target.value" />

v-model在组件上的使用

回到我们一开始的疑问了?vue中v-model如何进行父子组件的通信?如何在组件中使用呢?假如你理解了我上面的例子,那么,我们就可以很简单的在组件中使用v-model了。

父组件代码如下:

<template>
<div>
    实例:
    <span>{{dzrooms}}</span>
     <dz-model v-model="dzrooms"></dz-model>
</div>
</template>
 
<script>
import dzModel from './dzModel'
  export default {
    components:{
      dzModel,
    },
    data() {
      return {
        'dzrooms':'dzrooms'
      }
    }
  }
</script>

子组件代码如下:

<template>
  <div>
    
    <br />子组件
    <input
          ref="input"
          :value="value"
          @input="$emit('AnyName', $event.target.value)"
        >
  </div>
</template>
 
<script>
  export default {
      props: ["value"],
        model: {
            prop: 'value',
            event: 'AnyName'
        },
     data(){
            return{
            }
        },
       
 
  }
</script>

我们可以通过上面代码,子组件修改父组件v-model绑定的值!

实现截图如下:
在这里插入图片描述

v-model 的缺点和解决办法

在创建类似复选框或者单选框的常见组件时,v-model就不好用了。

<input type="checkbox" v-model="whyooms" />

我们可以用如下方式解决:

<input type="checkbox" :checked="status" @change="status = $event.target.checked" />

父组件可以如下写:

<my-checkbox v-model="whyrooms"></my-checkbox>

子组件:

<input  type="checkbox"
               <!--这里就不用 input 了,而是 任意名称-->
               @change="$emit('AnyName', $event.target.checked)"
               :checked="value"
             />

 export default {
        data(){
            return{
            }
        },
       props: ['checked'], //这里就不用 value 了,而是 checked
      model: {
          prop: 'checked',
          event: 'AnyName'
       },
    }

render 函数中的v-model

render 函数中没有与 v-model 相应的 api,根据上面的原理,可以自己实现!

render: function (createElement) {
  var self = this
  return createElement('input', {
    domProps: {
      value: self.value
    },
    on: {
      input: function (event) {
        self.value = event.target.value
        self.$emit('input', event.target.value)
      }
    }
  })
}

同步修饰符sync

为了保持单向数据流,vue2.0的sync已经成了阉割版,文档如下:如下代码

<comp :foo.sync="bar"></comp>

会被扩展为:

<comp :foo="bar" @update:foo="val => bar = val"></comp>

当子组件需要更新 foo 的值时,它需要显式地触发一个更新事件:

this.$emit('update:foo', newValue)

和上面v-model一样,.sync修饰符其实也就是一个语法糖。

Logo

前往低代码交流专区

更多推荐