在组件中实现v-model

v-model本质是语法糖,它负责监听用户的输入事件以更新数据,并对一些极端场景进行一些特殊处理。

1、v-model使用的属性和事件

v-model在内部为不同的输入元素使用不同的属性并抛出不同的事件

  1. input输入框(type为text)、textarea元素使用value属性和input事件
  2. checkbox、radio使用checked属性和change事件
  3. select下拉框使用value属性和change事件

2、自定义组件中输入框的v-model

在父组件中使用自定义组件myInput,使用v-model传入数据

<myInput v-model="name" />

以上写法相当于如下

<my-input :value="msg" @input="(e)=>{msg=e}"/>

v-model是value属性和input事件的语法糖

1、第一种写法

在组件的props中,通过value接收父组件v-model传过来的数据。
在输入时,通过$emit触发input事件,并将当前的输入值传过去,就会在父组件上触发input事件,并将传来的值赋给父组件上的值

<template>
  <div class="myInput">
    <input
      type="text"
      :value="value"
      @input="$emit('input', $event.target.value)"
    />
  </div>
</template>

<script>
export default {
  props: {
    value:{}
  },
};
</script>

2、第二种写法

一般以第一种写法就可以达到目的了。
一个组件上的 v-model 默认会利用名为 value 的 prop 和名为 input 的事件,但是像单选框、复选框等类型的输入控件可能会将 value attribute 用于不同的目的。使用model可以改变接收的属性名和抛出的事件名,model 选项可以用来避免这样的冲突

以input(type为text)标签的v-model为例,使用model后:

model: {
    prop: "xxxxx",
    event: "yyyyy",
  },

就将原来要接收的value属性改为了xxxxx属性,
原来要抛出的input事件,改为了yyyyy事件
所以,在props中接收xxxxx属性
触发事件时,触发yyyyy事件

<myInput v-model="name" />

此时就相当于如下代码

<my-input :xxxxx="msg" @yyyyy="(e)=>{msg=e}"/>
<template>
  <div class="myInput">
    <input
      type="text"
      :value="xxxxx"
      @input="$emit('yyyyy', $event.target.value)"
    />
  </div>
</template>

<script>
export default {
  model: {
    prop: "xxxxx",
    event: "yyyyy",
  },
  props: {
    xxxxx: String,
  },
};
</script>

一个组件中只能写一个输入框,因为v-model只能绑定一个数据;
如果想写一个组件,在组件内有多个输入框,就只能传一个对象给子组件了。

2、通过v-model控制组件的显示

在一些组件库中,一些组件例如dialog组件,可以通过v-model来控制dialog的显示与隐藏,这是怎么实现的?

isShow控制组件box的显示与否

<box v-model="isShow"/>

在box组件中,

  1. 通过props的value接收v-model传过来的值;
  2. 定义一个变量showModal,并将value的值同步赋值给它;
  3. 使用showModal控制组件的显示隐藏;
  4. 点击box组件时,将showModal设为false,同时触发input事件,并将当前的showModal值传过去;
  5. 父组件响应input事件,将v-model绑定的值赋值;
  6. div元素使用的是value属性和input事件(div元素可以变成输入框,它上面存在input事件)
<template>
  <div class="box" @click="hide" v-show="showModal"></div>
</template>

<script>
export default {
  props: {
    value: {
      type: Boolean,
    },
  },
  data() {
    return {
      showModal: false,
    };
  },
  watch: {
    value(val) {
      this.showModal = val;
    },
    showModal(val) {
      this.$emit("input", val);
    },
  },
  methods: {
    hide() {
      this.showModal = false;
    },
  },
};
</script>
  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值