逻辑强化系列(一): 彻底搞懂自定义组件上使用 v-model

386 阅读2分钟

v-model

在组件上使用 v-model 之前首先要知道,v-model 的用处以及实际操作流程,以方便理解,而不是死记硬背语法;

  • v-model 用途 你可以用 v-model 指令在表单input<textarea><select> 元素上创建双向数据绑定。 它会根据控件类型自动选取正确的方法来更新元素。尽管有些神奇,但 v-model 本质上不过是语法糖。它负责监听用户的输入事 件以更新数据,并对一些极端场景进行一些特殊处理。
  • v-model 实际操作 <input v-model="searchText"> 其实等价于 <input :value="searchText" @input="searchText = $event.target.value"> 下面那个 input 的代码的意思就是,在执行 input 事件的时候,将事件的 value 赋值给 searchText, 这正是第一段代码的意思,当 searchText 的变量值发生变动,其他依赖该变量值得地方也会变动,这就产生了一个完整的,用户输入->数据变动->用户界面变动 这样 一个双向绑定效果。 因此, v-model 实际上只是一个语法糖而已,让我们少写一些代码,VUE 中这类语法糖随处可见,之后还会经常接触

在自定义组件中使用

正常的在原生元素中使用,我们只需要直接添加即可,但是在组件中使用时,除了在父组件上添加该属性外,当然还需要子组件做一 些配合,下面是详细步骤:

父组件中设置 v-model

假定我们现在的 子组件叫做 my-input,需要联动的数据叫做 msg <my-input v-model="msg"></my-input>

export default {
        data() {
            return {
                msg: ''
            }
        }
    }

子组件中的配置

  • 首先需要接受一个叫做 value 的 prop , 因为父组件设置 v-model 的时候,默认就会给子组件传一个 value 的 prop,也就是这段 隐藏代码 :value="msg" @input="msg = arguments[0]"
    export default {
        props: ['value']
    }
  • 接着配置 input 元素,对于上述隐藏代码的后半部分(将用户输入赋值到 msg),我们自然是不能写在父组件上的,因此需要搬到真正有 input 元素的子组件中来完成
    <input type="text" @input="$emit('input', $event.target.value)">

此处的逻辑就是,通过 emit 去调用父组件的 input 事件(因为使用 v-model 语法糖,父组件的 input 事件已经定义,所以才可以这样去调用),并将用户输入的内容作为参数传入该 input 事件,这样就巧妙的实现了在子组件处监听用户输入并改变父组件的参数 msg 这样一个本来会相对复杂的逻辑过程! Tips: 理解这部分的关键点在于三个: 1、事件的起点是子组件上的原生 input 的 oninput 事件; 2、父组件这里的需求是,希望可以通过输入来改变 v-model 所绑定的变量值,然而其本身又没法直接获取到用户的输入,所以需要通过子组件调用 emit 方法传参来告诉它,用户输入的是什么; 3、v-model 这个语法糖本身是给原生的表单控件使用的,因为在原生表单控件上,用户输入和提供的变量都在同一作用域,都可以访问到,因此整个过程一气呵成,一个 v-model 就搞定了;但是当我们使用一个包装过的表单控件,比方说本文中 my-input 控件,就存在了一个作用域的问题,在父组件这里,我们定义了需要 v-model 帮我们改变的变量,然而却监控不到用户输入,用户输入在哪个作用域呢,答案是子组件处,而子组件需要如何让父组件知道呢,答案是 emit 函数;下面来看一下整个过程父子组件都分摊了哪些工作: 父组件: 绑定数据变量,通过 v-model 隐藏的代码定义了自身的 input 事件(对数据变量赋值),但是缺少事件的参数; 子组件:监听用户输入, emit 触发父组件 input 事件并将用户输入作为参数传入以便父组件对数据变量赋值