Vue3中的常见组件通信之v-model

Vue3中的常见组件通信之v-model

概述

​ 在vue3中常见的组件通信有props、mitt、v-model、 r e f s 、 refs、 refsparent、provide、inject、pinia、slot等。不同的组件关系用不同的传递方式。常见的撘配形式如下表所示。

组件关系 传递方式
父传子 1. props
2. v-model
3. $refs
4. 默认插槽、具名插槽
子传父 1. props
2. 自定义事件
3. v-model
4. $parent
5. 作用域插槽
祖传孙、孙传祖 1. $attrs
2. provide、inject
兄弟间、任意组件间 1. mitt
2. pinia

​ props和自定义事件详见本人另一篇文章:
Vue3中的常见组件通信之props和自定义事件
mitt用法详见本人另一篇文章:
Vue3中的常见组件通信之mitt
下面接着前面的文章继续记录v-model的用法。

4.v-model

v-model常用于普通html标签中的双向绑定,这个绑定用法无法实现跨组件通信,v-model用在组件标签中的时候,可以实现父子间的组件通信,而这样通信方式常用于UI组件库。要理解UI组件库的v-model的双向通信原理,需要先明白普通html标签中的v-model的底层原理。

4.1 普通HTML标签中v-model实现双向绑定的底层原理

在普通html标签中用v-model可以实现数据的双向绑定,如下代码所示是把input输入框里的数据与username进行双向绑定:

<template>
  <div class="father">
    <h3>父组件</h3>    
    <br>
    <input id="input1" type="text" v-model="username">
  </div>
</template>

<script setup lang="ts" name="Father">
	import { ref } from "vue"; 
  // 数据
  let username = ref('zhansan')

</script>

<style scoped>
.father {
  height: 300px;
  padding: 20px;
  color: #ffffff;  
  text-align:center; 
  background-image: url(https://xyyhxxx.oss-cn-beijing.aliyuncs.com/picGoImg/202406041301030.png);
  background-size: cover
}
#input1{
  color: #000;
}
</style>

运行后在浏览器打开vue开发者工具,如下图所示:

上图中更改vue开发者工具中的username的值页面也会跟着发生变化,这个实现的是把数据呈现在页面,如果修改input输入框中的内容,username的数据也会跟着发生改变,这个实现的是页面传向数据,这就双向绑定中的双向,而实现这个双向绑定的关键就是在于input标签中写了v-model,如下所示:

<input id="input1" type="text" v-model="username">

而上面的代码实现的底层原理是这样的,先把上面的代码改成如下图所示:

<input id="input1" type="text" :value="username">

这样可以实现数据呈现在页面,数据修改页面也会跟着修改,但是修改页面,数据却不会变化,这只实现了一个方向的数据绑定,接着再给input标签增加属性,如下代码:

<input 
       id="input1" 
       type="text" 
       :value="username" 
       @input="username=$event.target.value"
       >

这样再测试,就会发现页面中的数据也可以传向数据了,修改input标签中的内容,数据也会变化。

注意上面代码中@input="username= e v e n t . t a r g e t . v a l u e " 这句代码 t s 会报警,我们需要处理一下,对 event.target.value"这句代码ts会报警,我们需要处理一下,对 event.target.value"这句代码ts会报警,我们需要处理一下,对event.target进行断言,报警就会消失:

<input 
      id="input1" 
      type="text" 
      :value="username" 
      @input="username=(<HTMLInputElement>$event.target).value"
      >

普通input标签中v-model实现双向绑定的底层原理就是:value+@input事件。

4.2组件标签中v-model中实现双向绑定

首先准备一个自己的UI组件,作为子组件,代码如下:

<template>
    <input type="text">
</template>

<script setup lang="ts" name="MyInput">

</script>

<style scoped>
    input{
        background-color:transparent;
        color: #ffffff;
        border: 0px;
        border-bottom: 1px solid #ffffff ;
        margin: 5px;
    }
</style>

然后在父组件中引入:

//引入MyInput组件
  import MyInput from "./MyInput.vue";

在父组件中把MyInput组件呈现在页面中:

<label>用户名:<MyInput/></label>

运行效果如下:

image-20240604213607959

这样效果出来了,但是没有还没有实现数据绑定,首先在MyInput组件标签上增加:modelValue属性和绑定@update:model-value事件,如下代码:

<MyInput :modelValue="username" @update:model-value="username=$event"/>

然后需要在MyInput组件中声明props和声明事件来接收数据和事件:

//接收props
defineProps(["modelValue"])
//声明事件
let emit = defineEmits(['update:model-value'])

最后在MyInput组件中的普通html标签中添加:value属性和绑定@input事件:

<input 
       type="text" 
       :value="modelValue"
       @input="emit('update:model-value',(<HTMLInputElement>$event.target).value)"
>

至此,已经实现了父组件和子组件MyInput组件的双向通信,如下图所示:

最后在父组件中的MyInput组件标签上可以直接简写为如下代码:

<MyInput v-model="username"/>

实现的效果是完全一样的。

我们在用UI组件库的时候可以直接这样写,前提是UI组件库已经处理好了底层逻辑。

以下是完整代码:

父组件:

<template>
  <div class="father">
    <h3>父组件</h3>    
    <br>
    <!-- <input id="input1" type="text" v-model="username"> -->

    <!-- 下面是v-model 的本质 -->
    <!-- <input 
      id="input1" 
      type="text" 
      :value="username" 
      @input="username=(<HTMLInputElement>$event.target).value"
      > -->
    
    <!-- 下面是v-model 的本质 -->
    <!-- <label>用户名:<MyInput :modelValue="username" @update:model-value="username=$event"/></label> -->

    <label>用户名:<MyInput v-model="username"/></label>

  </div>
</template>

<script setup lang="ts" name="Father">
	import { ref } from "vue"; 
  //引入MyInput组件
  import MyInput from "./MyInput.vue";
  // 数据
  let username = ref('zhansan')

</script>

<style scoped>
.father {
  height: 300px;
  padding: 20px;
  color: #ffffff;  
  text-align:center; 
  background-image: url(https://xyyhxxx.oss-cn-beijing.aliyuncs.com/picGoImg/202406041301030.png);
  background-size: cover
}
#input1{
  color: #000;
}
</style>

MyInput组件:

<template>
    <input 
        type="text" 
        :value="modelValue"
        @input="emit('update:model-value',(<HTMLInputElement>$event.target).value)"
    >
</template>

<script setup lang="ts" name="MyInput">
    //声明props
    defineProps(["modelValue"])
    //声明事件
    let emit = defineEmits(['update:model-value'])
</script>

<style scoped>
    input{
        background-color:transparent;
        color: #ffffff;
        border: 0px;
        border-bottom: 1px solid #ffffff ;
        margin: 5px;
    }
</style>

4.3一个UI组件实现多个数据传送

在父组件中可以改value,比如改成usName,如下代码所示:

<MyInput v-model:usName="username"/>

这个代码的本质是如下代码:

<MyInput :usName="username" @update:usName="username=$event"/>

在MyInput组件代码中就需要改成如下代码:

<template>
    <input 
        type="text" 
        :value="usName"
        @input="emit('update:usName',(<HTMLInputElement>$event.target).value)"
    >
</template>

<script setup lang="ts" name="MyInput">
    //声明props
    defineProps(["usName"])
    //声明事件
    let emit = defineEmits(['update:usName'])
</script>

这样改完后运行效果跟之前是完全一样的,接下来再扩展一下,父组件中的MyInput标签改成如下代码:

<MyInput v-model:usName="username" v-model:paword="password"/>

然后在MyInput组件中代码改成如下:

<template>
    <input 
        type="text" 
        :value="usName"
        @input="emit('update:usName',(<HTMLInputElement>$event.target).value)"
    >
    <br>
    <input 
        type="text" 
        :value="paword"
        @input="emit('update:paword',(<HTMLInputElement>$event.target).value)"
    >
</template>

<script setup lang="ts" name="MyInput">
    //声明props
    defineProps(["usName",'paword'])
    //声明事件
    let emit = defineEmits(['update:usName','update:paword'])
</script>

这样就实现一个组件内双向绑定两个数据了,如下图所示:

4.4小结

v-model可以实现父子间的通信,v-model即可以设置在普通html标签中,也可以设置在组件标签中,设置在组件标签中可以实现父子间的双向通信,前提是子组件底层做了处理。

相关推荐

  1. 详解vue3组件 v-model

    2024-06-06 09:34:04       39 阅读
  2. vue3组件v-model参数

    2024-06-06 09:34:04       36 阅读
  3. vue2和vue3v-model

    2024-06-06 09:34:04       44 阅读

最近更新

  1. docker php8.1+nginx base 镜像 dockerfile 配置

    2024-06-06 09:34:04       94 阅读
  2. Could not load dynamic library ‘cudart64_100.dll‘

    2024-06-06 09:34:04       100 阅读
  3. 在Django里面运行非项目文件

    2024-06-06 09:34:04       82 阅读
  4. Python语言-面向对象

    2024-06-06 09:34:04       91 阅读

热门阅读

  1. Qt5学习笔记

    2024-06-06 09:34:04       27 阅读
  2. RabbitMQ 如何保证消息不丢失

    2024-06-06 09:34:04       35 阅读
  3. 服务器硬件基础知识

    2024-06-06 09:34:04       31 阅读
  4. 深入理解HTTP与TCP:应用层与传输层的区分

    2024-06-06 09:34:04       31 阅读
  5. 【计算机网络】 传输层

    2024-06-06 09:34:04       32 阅读
  6. 在ros中获取话题的发布节点名称(C++)

    2024-06-06 09:34:04       25 阅读
  7. 多单页应用的构建优化-按entry拆分构建

    2024-06-06 09:34:04       33 阅读
  8. 【解决方案】前端React 、Vue工程如何开启GZIP压缩

    2024-06-06 09:34:04       30 阅读
  9. Linux云计算实践:OpenStack与云服务

    2024-06-06 09:34:04       30 阅读