问题
I'm trying to make a wrapper component for an <input/>
element in Vue.js.
Component:
<template>
<div>
<input v-bind="$attrs" :value="value" @input="input" />
...
</div>
<template>
Vue.component("my-input", {
inheritAttrs: false,
props: ['value'],
methods: {
input($event): void {
this.$emit("input", $event.target.value)
}
}
})
Usage:
<my-input v-model="myModel" />
This seems to work just fine. The model gets updated via the input event handler by emitting the target element value.
However, now I'm trying to use this component with some existing code:
<my-input v-model="myModel2" @input="something = $event.target.value" />
This is where I'm having trouble with the $emit("input")
event. I'm getting the following error:
Cannot read property 'value' of undefined
So, my $emit
is emitting the value and now the existing @input="something..."
event handler can't reference the $event
properly.
If I change my component's input
method to emit the $event
instead of $event.target.value
, the new code seems to work, but then model doesn't get updated gets updated to the InputEvent instead of the actual value.
I'm not sure what I need to do.
回答1:
When you $emit('input')
and the value is tied to a v-model
of a text input, the value of the <input>
will be updated to whatever you emitted. In the case of $emit('input', $event.target.value)
, it's the value of the text in the <input>
that you are emitting. This value will be intercepted in the parent, as v-model
effectively does: <my-input :value="inputValue" @input="inputValue = $event">
This means the value of the <input
> will get bound back to the <input>
(effectively causing no change to the value in the input). If, however, you $emit('input', $event)
, then v-model
will still capture whatever value is passed up and update the value of the <input>
with it. In this case, it will be the actual input event object, as you've said.
If you don't want to use the input
event tied to your model, you could always use a custom v-model event. Then you'd be able to $emit('input', $event)
and not have it affect the v-model value, instead you'd update the v-model from $emit('custom-event', $event.target.value)
回答2:
Try
<my-input v-model="myModel2" @input="value => something = value" />
回答3:
Just assign them from parent directly instead of creating proxies
const MyInput = Vue.extend({
name: 'MyInput',
template: '#ins',
data(){return{valid: true}},
methods: {validate(ev){this.valid = ev.target.value.length < 1 ;this.$listeners.input(ev)}}
})
const App = Vue.extend({
components: {
MyInput
},
template: '#myinput',
data(){return{val: 'test'}},
methods: {ins(ev){console.log(ev.target.value)}}
})
new Vue({
name: 'root',
render: h => h(App)
}).$mount("#app");
input {background: red}
.valid{background:green !important}
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app"></div>
<template id="ins">
<input v-bind="$attrs" @input="validate" :class="{valid:valid}"/>
</template>
<template id="myinput">
<my-input v-model="val" @input="ins" />
</template>
来源:https://stackoverflow.com/questions/56953243/vue-component-v-model-with-input-handler