今天被Vue的 v-model 给绕了一下,特在此记录一下;
https://cn.vuejs.org/v2/guide/components.html
下面是原文
定义事件也可以用于创建支持 v-model
的自定义输入组件。记住:
|
等价于:(切记切记, searchText 是 input组件父组件的一个属性,因为我自己用 Ts 写组件时,总是很容易搞混)
|
当用在组件上时,v-model
则会这样:
(切记切记, searchText 是custom-input组件父组件的一个属性,因为我自己用 Ts 写组件时,总是很容易搞混)
|
这儿没有触发父组件任何的事件,而只是单纯的设置了 父组件的某一个属性;
并且,Vue对于原生的 Html Form元素和我们自己定义的 Vue - Componet 是进行了不同的处理的;
因为两处的 V-model 的代码是不一样的。。
这样,我们自己定义的组件,当绑定父组件的属性后,在input元素的值发生改变时,
必须能够接收一个内部 input 元素抛出的 input 事件,以便触发我们自己定义元素 (custom-input) 的 v-on:input 事件处理函数;
也就是Vue文档所说的:
为了让它正常工作,这个组件内的 <input>
必须:
- 将其
value
特性绑定到一个名叫value
的 prop 上 - 在其
input
事件被触发时,将新的值通过自定义的input
事件抛出
写成代码之后是这样的:
|
组件里面包含有原生的 input 元素的时候,很容易理解,
就是在 原生input元素触发 input 事件时,调用 $emit('input', $event.target.value)
触发父元素的 input 事件,
而父元素的 v-model 类似于 , v-on:input="searchText = $event"
//这儿的 $event 很明显已经不是 $event, 根据 input 元素的代码, $emit('input', $event.target.value) , 而是 input 元素里面的 value;
所以,searchText=value; 就获取到了元素的值了;
而这个 searchText 是包含 custom-input 的 vue组件 里面的属性,所以啊,貌似工作的很好;
很好,但世界不是这么简单。。
还是上面的代码,
Vue.component('custom-input', {
props: ['value'],
template:
` <input v-bind:value="value"
v-on:input="$emit('input', $event.target.value)" > `
}
)
Vue.component('wrap-custom-input', {
props: ['value'],
template:
` <custom-input v-model="value"> `
}
)
假如我把这个组件用到父组件里面,
也就是 :
<wrap-custom-input v-model='name'></wrap-custom-input>, 在输入框中输入了 abc 时,
使用 wrap-custom-input 的父组件里面的 name 的属性会是啥?
貌似也应该是 abc; 但是很可惜,不是;
为啥呢??
看看事件流程啊, 最里面的 input 元素输入了 abc 时,触发 input 元素的 v-on:inpu 事件,
也就是这一行代码: v-on:input="$emit('input', $event.target.value)"
然后触发了, customer-input 的 on:input 的事件处理,
v-on:input="value= $event"
这个没有疑问; 然后,就没有然后了。。
当然,不考虑警告的话,
(因为 vue 对于 Prop 不建议直接在子组件中直接修改(估计,以后会禁止直接修改)
customer-input 会设置父组件 wrap-custom-input 的 value,
而父组件 wrap-custom-input 的 value 又会去设置 wrap-custom-input 父组件的 name 属性,
这样,也能够间接修改 name 属性,
可惜,vue不喜欢警告,我也不喜欢;
咋样去除警告呢?
类似的,把 wrap-custom-input 的代码改成如下所示, 不就可以了。。
Vue.component('custom-input', {
props: ['value'],
template:
` <input v-bind:value="value"
v-on:input="$emit('input', $event.target.value)" > `
}
)
Vue.component('wrap-custom-input', {
props: ['value'],
template:
` <custom-input v-model="value" v-on:input="$emit('input', $event)> `
}
)
以上只是猜想,实际验证一下呃。。
https://jsfiddle.net/hesi726/eywraw8t/418184/
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Vue 测试实例 - 菜鸟教程(runoob.com)</title>
<script src="https://cdn.staticfile.org/vue/2.4.2/vue.min.js"></script>
</head>
<body>
<div id="app">
<p>{{ message }}, Name: {{name}}, Abc: {{abc}}</p>
V-model=Abc: <custom-input v-model='abc'></custom-input><br/>
V-model=name: <wrap-custom-input v-model='name'></wrap-custom-input>
</div>
<script>
Vue.component('custom-input', {
props: ['value'],
template:
`<input v-bind:value="value" v-on:input="$emit('input', $event.target.value)" >`
}
);
Vue.component('wrap-custom-input', {
props: ['value'],
template:
`<custom-input v-model="value" v-on:input="$emit('input', $event)"></custom-input>`
}
);
new Vue({
el: '#app',
data: {
abc: '',
name: '',
message: 'Hello Vue.js!'
}
})
</script>
</body>
</html>