在( 自定义 )组件上使用 v-model

v-model 本质上不过是语法糖:它负责监听用户的输入事件以更新数据,并对以下极端场景作出特殊处理。

简单来说就是:在内部为不同的输入元素使用不同的属性并抛出不同的事件


v-model 默认情况下,只接受 value 属性和响应 input 事件 — 因为 v-model 本身就是基于 input 定制的,而,value 属性是 input 内部定制的绑定值的属性,input 事件是内部定制的当值发生改变时触发的事件。


// HTML
   {{msg}}
   // 下面两个表达式,实现的是同样的效果
   <input type="text" v-model="msg">
   <input type="text" :value="msg" @input="msg = $event.target.value">
   // 所以说,v-model 只不过是一种语法糖的形式:
   // input 组件上本身就有一个 oninput 事件,每当输入框内容发生变化的时候,就会触发这个事件,然后把input的值通过@emit传递出去。

// JS
   data(){
     return {
       msg:'测试内容'
     }
   }

使用场景:子组件想要使用父组件的值,又想去修改父组件的值

# 实现方式 1( 常规 ):props  +  $emit    /    实现方式 2( 语法糖 ):v-model

// 父组件

<template>
  <div id="app">
    <!-- 常规方式 -->
    <Child :value="msg" @input="msg = $event"></Child>
    <!-- v-model 语法糖 -->
    <Child v-model="msg"></Child>
  </div>
</template>

<script>
import Child from './components/child'
export default {
  name: "App",
  data(){
    return {
      msg:'测试内容'
    }
  },
  components:{
    Child
  }
};
</script>
// 子组件

<template>
  <div class="content">
      {{value}}
      <div @click="clickBtn">点击</div>
  </div>
</template>

<script>
export default {
  props:{
      value:''
  },
  methods:{
      clickBtn(){
          this.$emit('input','子组件内容')
      }
  }
}
</script>

# 实现方式 3:定制 v-model - model 选项

Problem:子组件中的 value 属性被占用了,如何实现 v-model ?

  • 官网解释:model 选项,允许一个自定义组件在使用 v-model 时定制 prop 和 event。
    • 默认情况下,一个组件上的 v-model 会把 value 用作 prop 且把 input 用作 event, 但是一些输入类型,比如单选框和复选框按钮可能想使用 value prop 来达到不同的目的。
  • 使用 model 选项可以回避这些情况产生的冲突。
// 父组件

<template>
  <div id="app">
    <!-- v-model 语法糖 -->
    <Child v-model="msg"></Child>
  </div>
</template>

<script>
import Child from './components/child'
export default {
  name: "App",
  data(){
    return {
      msg:'测试内容'
    }
  },
  components:{
    Child
  },
};
</script>
// 子组件

<template>
  <div class="content">
      {{msg1}}
      <input type="text" :value="msg1" @input="$emit('change1',$event.target.value)">
  </div>
</template>

<script>
export default {
  props:{
      msg1:''
  },
  model:{
    prop:'msg1',
    event:'change1'
  }
}
</script>