先看看直接包装input时,官网的例子吧!
我的理解:
在代码1中,v-model="searchText" 是一个语法糖。代表了代码2中的v-bind:value="searchText" v-on:input="searchText = $event.target.value",所以代码1和代码2是完全等价的。
(语法糖是什么?嗯...我当它用一种特定语句,代表一些操作。)
同理,代码3和代码5是完全等价的,区别是代码1是原生input,代码5是对input进行了包装的组件。
那么关键点在于custom-input这个组件内部,是怎么运作,才使v-model这个语法糖能够生效。
v-model如何生效的思路如下:
- 代码5和代码3等价,所以组价加载时,v-bind:value="searchText"将searchText的值绑定到了custom-input组件内部props的value属性,代码4中可以看到props的value属性
- 代码4中,v-bind:value="value"从props中的value取值,绑定到input的value值上,然后当input输入了内容,触发input事件,v-on:input="$emit('input', $event.target.value)"语句定义input事件,传递最新的内容到父组件。(这整个过程,没有修改props中value的值,不违背vue的单向数据流原则)
- 父组件中,v-on:input="searchText = $event"语句接收了input事件传递的值,设置到searchText中。
对于custom-input这样的组件,如果进行二次包装,应该怎么使包装后的组件上v-model正常使用?
核心思想是在包装后的组件上,v-model语法糖正常可以使用,即保证在封装后的组件上,v-bind:value="searchText"可以正常绑定一个值, v-on:input="searchText = $event"可以正常获取到组件内部传递的值然后赋值给searchText。
例子如下:
假定已经对input封装过的组件为el-input,el-input的内部实现不需要关心
ValidateInput实现
<template>
<!-- 对el-input进行了包装-->
<div>
<el-input
v-model="localValue"
@input="$emit('input', $event)"></el-input>
<!--
el-input提供了input事件,让我们感知el-input内部原生input值的变化,通过$event可以获取到具体的值
通过emit再次传递给父组件一个input事件,父组件中,v-on:input="searchText = $event"这句就能正常使用了
-->
<span style="color: #f56c6c; font-size: 12px;"></span>
</div>
</template>
<script>
export default {
name: "elValidateInput",
props: {
// 保证父组件中,v-bind:value可以正常设置值
value: [String],
},
data() {
return {
// 获取props中value的值,并与el-input绑定,过程中不修改props中value的值,保证了单向数据流原则
localValue: this.value
}
}
}
</script>
<style lang="scss" scoped>
</style>
引用ValidateInput
<validate-input
v-model="testData"
></validate-input>
<!--上下代码等价-->
<validate-input
v-bind:value="testData"
v-on:input="testData= $event"
></validate-input>
完成
通过vue文档中自定义组件的 v-model
一节,应该还能实现的更优雅些。懒得写了 - - ...