Vue组件通信之v-model

文章目录

总结

  • v-model 的本质是 v-bind 加上 @input ,实现数据双向绑定
  • 父组件和子组件之间通信:
    • 通过 props 自定义属性,实现从父到子的数据传送
    • 通过 emit 自定义事件,实现从子到父的数据传送
    • 二者相结合,实现父子组件之间的数据双向绑定
  • 在父组件里,可以简化 为v-model 操作,前提是子组件emit的事件必须是 update:xxx
  • v-model 的默认参数(即绑定的属性名)是 modelValue
    • 对于原生HTML元素, v-model 无需指定属性名,因为Vue知道取哪个属性名
  • 同一个子组件里可通过多个v-model 绑定多个属性,只需用参数区分开

环境

  • Ubuntu 24.04
  • Chrome Version 146.0.7680.164 (Official Build) (64-bit)
  • VSCode 1.109.5
  • npm 11.6.2
  • Vue 3.5.32

准备

创建一个Vue项目。创建过程略,具体可参见 https://blog.csdn.net/duke_ding2/article/details/159510007 。

关于props,参见 https://blog.csdn.net/duke_ding2/article/details/159696940 。

关于emit,参见 https://blog.csdn.net/duke_ding2/article/details/159779784 。

v-model

基础

修改 App.vue 如下:

html 复制代码
<template>
    <div>
        <input v-model="searchText" />
        <div>{{ searchText }}</div>
        <button @click="searchText = Math.random()">随机数</button>
    </div>
</template>

<script>
export default {
    data() {
        return {
            searchText: ''
        }
    }
}
</script>

效果如下:

  • 点击按钮时,生成一个随机数:
  • 用户可以修改输入框的数据:

本例中,通过 v-model ,实现了数据(变量 searchText )与显示的"双向绑定":

  • 当数据的值变化时(比如点击按钮,生成随机数),输入框里的数据会同步变化
  • 当输入框里的数据被修改时,数据的数值会同步变化

注意这行代码:

html 复制代码
<input v-model="searchText" />

模板编译器会对 v-model 进行更冗长的等价展开。因此上面的代码其实等价于下面这段:

html 复制代码
<input
  :value="searchText"
  @input="searchText = $event.target.value"
/>

其中:

  • :value 表示从 searchText 变量到输入框显示的绑定
  • @input 表示在编辑输入框时,把数据修改同步到 searchText 变量

组件

在使用子组件时,要想把"父组件里的数据"和"子组件里的显示"做双向绑定,同理也需要 :value 和 @input ,但不同的是:

  • :value :由于其来源是父组件,所以需要通过 props 设置自定义属性
  • @input :由于其目的是父组件,所以需要通过 emit 把事件发送到父组件

创建 MyComponent.vue 文件如下:

html 复制代码
<template>
    <input :value="searchText" @input="$emit('update:searchText', $event.target.value)"/>
</template>

<script>
export default {
    props: ['searchText'],
    emits: ['update:searchText'],
}
</script>

可见,在子组件中,通过 props 接受父组件的数据,通过 emit 向父组件发送"数据修改"事件。

注意:本例中,emit的事件名是 update:searchText ,其实在本例中并不强制如此。

修改 App.vue 如下:

html 复制代码
<template>
    <div>
        <MyComponent :searchText="searchText" @update:searchText="newValue => searchText = newValue"/>
        <div>{{ searchText }}</div>
        <button @click="searchText = Math.random()">随机数</button>
    </div>
</template>

<script>
    import MyComponent from './MyComponent.vue';
    export default {
        components: {
            MyComponent
        },

        data() {
            return {
                searchText: ''
            }
        }
    }
</script>

可见,在父组件中,通过自定义属性 :searchText 向子组件传送数据,通过自定义事件 @update:searchText 接收子组件的"数据修改"事件,并同步修改变量 searchText 。

这样,就实现了父组件数据和子组件显示之间的双向绑定。

注意:本例中,自定义事件名是 update:searchText ,其实换成的其它如 updateSearchText 也没有问题。

v-model

之所以使用 update:searchText 这种看起来有点"怪异"的写法,是因为在Vue里,使用这种方法,则在父组件可以简化为 v-model 操作。

找到 App.vue 的如下代码:

html 复制代码
<MyComponent :searchText="searchText" @update:searchText="newValue => searchText = newValue"/>

将其修改为:

html 复制代码
<MyComponent v-model:searchText="searchText"/>

同样也能达到双向绑定效果。

只需记住 update:xxx 是固定的写法。这样父组件就可以通过 v-model 来简化。

参数与默认绑定属性名

上面的例子里, v-model 有一个参数 searchText ,该参数代表绑定的属性名。

注意:在本例中,该参数不能省略:

html 复制代码
<MyComponent v-model="searchText"/>

这是不行的,因为Vue需要知道绑定的属性名是什么。如果不显式指定,则缺省绑定的属性名是 modelValue 。

也就是说,如果子组件只接收一个自定义属性,则为了简化,可以将其命名为 modelValue ,此时父组件的 v-model 可以省略参数。

注意:文本开头的例子里,并没有指定属性名:

html 复制代码
<input v-model="searchText" />

这是因为对于原生的HTML元素,Vue知道应该绑定哪个属性名。比如,对于 input ,默认绑定的属性名是 value 。

多个v-model绑定

既然通过参数可以区分不同的属性名,我们就可以在一个子组件里通过 v-model 绑定多个属性。

修改 MyComponent.vue 如下:

html 复制代码
<template>
    <div>
        <input :value="searchText" @input="$emit('update:searchText', $event.target.value)"/>
        <br />
        <input :value="searchTitle" @input="$emit('update:searchTitle', $event.target.value)"/>
    </div>
</template>

<script>
export default {
    props: ['searchText', 'searchTitle'],
    emits: ['update:searchText', 'update:searchTitle'],
}
</script>

修改 App.vue 如下:

html 复制代码
<template>
    <div>
        <MyComponent v-model:searchText="searchText" v-model:searchTitle="searchTitle"/>
        <div>{{ searchText }}</div>
        <div>{{ searchTitle }}</div>
        <button @click="searchText = Math.random()">随机数</button>
        <button @click="searchTitle = Math.random()">随机数</button>
    </div>
</template>

<script>
    import MyComponent from './MyComponent.vue';
    export default {
        components: {
            MyComponent
        },

        data() {
            return {
                searchText: '',
                searchTitle: ''
            }
        }
    }
</script>

效果如下:

参考

  • https://cn.vuejs.org/guide/components/v-model.html
相关推荐
福兮说6 小时前
前端下载大文件,点了按钮半天没反应:fetch + blob 的三个问题和三种替代写法
前端·javascript·性能优化·文件下载
GreenTea6 小时前
我把 Agent 的 while 循环拆掉了:一种你可能没想到的 Agent 架构
前端·后端·架构
科技观察哨6 小时前
六足平台选型与纳米定位系统集成:HEB-640六自由度位移台在半导体光刻对准中的参数边界与国产替代评估
前端·人工智能
niucloud-admin6 小时前
JAVA V6 多商户商城 开发文档——web前端
前端
颜进强7 小时前
16 · NestJS LifecycleEvents 生命周期事件:五个钩子、三条边界,和 rag-server 的优雅停机
前端·后端·ai编程
今年下半年8 小时前
【VUE】整合腾讯地图、自定义区域边界、村委名称及资产统计(放大显示资产点位)
前端·javascript·vue.js
郑州光合科技余经理8 小时前
同城电商系统:库存变更怎么同步到订单
java·开发语言·前端·后端·uni-app·php·ai编程
前端snow10 小时前
ai agent --- DeepAgents 中间件
前端
data analyse 45611 小时前
报表能自定义的国内统计工具有哪些
前端·数据分析