vue 自定义组件v-model双向绑定和父子组件同步通信

作者: 小疯子 分类: Vue 发布时间: 2019-02-18 23:08

一、起因

看Vue教程的时候看到这一篇https://cn.vuejs.org/v2/guide/components-custom-events.html(自定义事件->自定义组件的v-model)这一part的时候没有看懂什么意思,就去搜索了解一下;

二、基本介绍

关于v-model, 用 v-model 指令在表单 <input><textarea> 及 <select> 元素上创建双向数据绑定。它会根据控件类型自动选取正确的方法来更新元素。尽管有些神奇,但 v-model 本质上不过是语法糖。它负责监听用户的输入事件以更新数据,并对一些极端场景进行一些特殊处理。
语法糖具体定义我没有深入了解,应该就是一种便捷写法<input v-model="something">中的v-model指令其实是下面的语法糖包装而成的:

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

这里面的冒号后的value和input都是默认写好的值,不会更改

同理,如果想要在调用一个子组件custom-input的时候使用v-model,那本质上就是如下的写法:

<custom-input
  :value="something"
  @input="value => { something = value }">
</custom-input>

因此,对于一个带有v-model的组件,它应该有以下功能,按照上面的代码总结出的:第一是接受一个value的prop,第二是触发input事件,并传入新值。

三、父子组件通过v-model通信

(1)写法一

定义一个父组件:

<template>
  <div>
    <aa class="abc" v-model="test" ></aa>  // 组件中使用v-model
      {{'外面的值:' + test}} // 这儿试验test与内部msg值为双向绑定关系
    <button @click="fn">
      外面改变里面
    </button>
    
  </div>
</template>

<script>
import aa from './test.vue'
  export default {
    data () {
      return {
        test: ''
      }
    },
    methods: {
      fn () {
        this.test += 1 
      }
    },
    components:{
      aa
    }
  }
</script>

子组件:

<template>
  <div>
    <ul>
      <li>{{'里面的值:'+ msg}}</li>
      <button @click="fn2">里面改变外面</button>
    </ul>
  </div>
</template>

<script>
  export default {
    model: {    // 使用model, 这儿2个属性,prop属性说,我要将msg作为该组件被使用时(此处为aa组件被父组件调用)v-model能取到的值,event说,我emit ‘cc’ 的时候,参数的值就是父组件v-model收到的值。
      prop: 'msg',
      event: 'cc'
    },
    props: {
      msg: ''
    },
    methods: {
      fn2 () {
        this.$emit('cc', this.msg+2)
      }
    }
  }
</script>

上面的prop\event等就是在官网文档中没看懂的那一部份,如下所示:
下面来解释一下上面的代码,父组件调用的时候除去语法糖的话差不多应该是这样<aa class="abc" :value="test" @input="value => { test = value }" ></aa>,(value => { test = value }是我自己编的抑或是默认的,没有实战不大清楚后期再补充,正常也是会写一个函数代替它,比如叫parentmethod1, 在父组件的method模块中加上这个方法进行更复杂一些的操作) 但是这里的value和input都是默认的,因为单选框和复选框等组件中如果用value的话会与原有的产生混淆,所以不要用原始的value,在上面的例子中用的就是msg,而input也改成了cc,<aa class="abc" :msg="test" @cc="value => { test = value }" ></aa>

一下是官网自定义组件的v-model的部份


自定义组件的 v-model
一个组件上的 v-model 默认会利用名为 value 的 prop 和名为 input 的事件,但是像单选框、复选框等类型的输入控件可能会将 value 特性用于不同的目的model 选项可以用来避免这样的冲突: Vue.component('base-checkbox', {
  model: {
    prop: 'checked',
    event: 'change'
  },
  props: {
    checked: Boolean
  },
  template: `
    <input
      type="checkbox"
      v-bind:checked="checked"
      v-on:change="$emit('change', $event.target.checked)"
    >
  `
}) 现在在这个组件上使用 v-model 的时候: <base-checkbox v-model="lovingVue"></base-checkbox> 这里的 lovingVue 的值将会传入这个名为 checked 的 prop。同时当 <base-checkbox> 触发一个 change 事件并附带一个新的值的时候,这个 lovingVue 的属性将会被更新。 注意你仍然需要在组件的 props 选项里声明 checked 这个 prop。

(2) v-model写法二

父组件

<aa class="abc" v-model='test' ></aa>

子组件

<template>
  <div>
    <ul>
      <li>{{'里面的值:'+ value}}</li> // 组件使用时有v-model属性,value初始传的‘what’ 不会被渲染,而是v-model绑定的test值被渲染,这儿value会被重新赋值为v-model绑定的test的值。
      <button @click="fn2">里面改变外面</button>
    </ul>
  </div>
</template>

<script>
  export default {
    props: {
      value: { // 必须要使用value
     default: '',
    },
    },

    methods: {
      fn2 () {
        this.$emit('input', this.value+2) // 这儿必须用input 发送数据,发送的数据会被父级v-model=“test”接受到,再被value=test传回来。
      }
    }
  }

参考链接:https://www.cnblogs.com/gsgs/p/7294160.html

0