正文
首先我们来看一段代码:
<input value="value">
这里是一个原生的 input 输入框,每一个原生的输入框都会有一个 value 的属性来用于存储用于输入的最新的数据。
如果我们想要获取到这个值我们可以通过 input.target.value 或者通过 $event.target.value 来获取这个存储的值。
只要用户输入了数据,那么此时 input 标签就会将输入的数据放到这个 value 中(新数据会覆盖旧数据,所以我们获取到的都是最新的)。
现在我们来看上面的标签,我们为 input 标签添加了一个 value 属性,并且赋值 'value' 。其实在标签上设置 value 属性它的作用有两个:
在第一次创建 input 标签的时候,将对应的初始值展示到输入框中 (在无该属性使输入框不展示任何数据) 使用 value 属性的初始值来初始化 input.target.value (无该属性时 input.target.value 为空串)上面的那段代码的意思是通过添加 value="value" 属性,初始化 input.target.value 的值并且将初始值展示到对应的输入框中
这里需要注明一点,在后续用户输入的操作中,输入框中的数据只是方便让用户看到自己输入了什么仅此而已。 有人可以会有疑问,难道不是 input.target.value 里是什么所以输入框内就显示什么吗?其实不是的。
输入框显示什么和 input.target.value 并没有直接联系,输入框内的显示只是方便用户自己看到自己输入了什么。
小结:
input 中的 value 有两种: value="xxx" 和 input.target.value 我们需要知道两个分别有什么作用。在整个输入显示流程中, 他们分别扮演什么角色。
现在我们来看在 vue 中的输入框,首先我们来看一段代码:
<input v-bind:value @input="value = $event.target.value" /> data(){ return { value:'123' } }
我们一般使用 v-bind:value 来给 Input 标签绑定一个 vue 中的的,这里我们绑定的是 this.value 。 在这里 v-bind:value === :value="value" 。 这样实现的原理比较简单。
首先我们定义了 this.value 因为将 this.value 绑定到了 :value 上,所以初始时会在输入框展示我们指定的 值,即 '123' 。当我们输入数据之后,此时 $envet.target.value (这里的 $event.target.value 就是 input.target.value )就会存储我们最新的输入的值,然后将最新的值赋值给 this.value 。
因为 this.value 变化了,此时 vue 对页面进行更新,此时更新后的 input 的 :value 是最新值。
但是这里有一个问题,那就是 <input> 并不会被销毁重建,也就是说 this.value = $event.target.value 只是改变了 this.value 若别的地方引用了 this.value ,那么就会同步改变。那么 this.value 的更新对 :value="value" 的影响是什么呢?其实没有什么影响。
因为我们前面说了, :value 的作用有两个:一是初始化 input.value 的值,二是将初始值渲染到对应的输入框中。 在一开始将 this.value 作为初始值给 Input.value 和展示在框里,他的任务已经完成了,后续的更改对 :value 没有一点关系。
其实 :value="value" 的唯一作用就是将 this.value 作为初始值绑定和展示到 input 上。
v-model
现在对于原始元素进行算双向数据绑定已经完成。那么如何实现父组件和子组件之间的双向数据绑定嗯? 此时我们需要在子组件中使用v-model。 关于 v-model 的使用这里不再赘述。这里只讨论如何在自定义组件实现 v-model。根据vue 的官网的描述,我们大概知道,v-model 的本质就是语法糖,即:
<input type="text" v-model="name"> 相当于: <input type="text" :value="name" @input="name = $event.target.value">
vue 监听输入框输入行为然后改变对应的值。 如果对子组件进行双向数据绑定该如何实现呢?这里的双向数据绑定指的是父组件将值传递给子组件使用,并且子组件可以改变父组件的值 其实上述的双向绑定可以通过 v-bind:propName.sync = 'xxx' 来实现。 除了以上的方式,并且 Vue 还给我们提供了另一种方式:
<!-- 父组件.vue --> <child-component :propName="data" @change="change" /> export default { data(){ data:'123' }, methods:{ change(value){ this.data = value } } }
//在组件中如何想要改变父组件的值,那么直接出发对应的事件即可: this.$emit('change', newValue )
在 vue 中,它将上述的方法进行了简化,我们可以使用 v-model 来对子组件进行双向数据绑定。例如:
<child-component v-model="pageTitle" /> <!-- 是以下的简写: --> <child-component :value="pageTitle" @input="pageTitle = $event" />
在默认情况下 v-model 的触发事件名称为 input 。 子组件想要使用的话,需要定义一个名为 value 的 prop 才能使用。 而在子组件中更改该值,只需要定义一个函数,有必要的时候执行 this.$emit('input', newValue) 即可。
这里的 newValue 就是 $event 。 这样就可以改变对应的值。 当然除了默认的 value 和 input 的命名, vue 还给我们提过了更加灵活的方式。
<!-- 父组件 --> <child-component v-model="pageTitle" />
//子组件 export default { model: { prop: 'title', //这里相当于别名,这里可以起其他名称 event: 'change' //这里相当于事件的别名,这里可以起其他名称 }, props: { // 这将允许 `value` 属性用于其他用途 value: String, // 使用 `title` 代替 `value` 作为 model 的 prop title: { type: String, default: 'Default title' } } }
当我们想在子组件中改变传入的值,那么直接可以 this.$emit('change', newValue)
所以,在这个例子中 v-model 是以下的简写:
<child-component :title="pageTitle" @change="pageTitle = $event" />
其实本质上,项目中的 twowayFactor 这个混入配置类,他本质上就是做了上面的操作。
@Prop() @Model('valueChanged') bindValue!: T;
这样做的目的是将 v-model 传入的 prop 改为 bindValue 。 然后将默认事件的名称从 input 改为了 valueChange 。 接着设置 get/set
get currentValue() { return this.bindValue; } set currentValue(value) { this.$emit('valueChanged', value); }
这样做的目的是数据本地化。 在组件内部定义一个 currentValue 然后为该值设置 get ,当访问 currentValue 等价于访问 v-model 的 prop 。 然后设置 set 。当改变 currentValue 的值时,此时就会触发对应的事件。 当触发之后父组件中的值就会变化。这就实现了双向数据绑定。
我们可以看到,其实 this.currentValue 的作用就是 v-model 操作的语法糖。 它并没有什么特别之处,只是将 v-model 传入的数据的访问和更改简单化了,都集中与一个值 this.currentValue 。
以上就是vue原生input输入框原理剖析的详细内容,更多关于vue原生input输入框的资料请关注其它相关文章!
查看更多关于vue原生input输入框原理剖析的详细内容...