简体   繁体   中英

Vue component v-model with input handler

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 modeldoesn't get updatedgets updated to the InputEvent instead of the actual value .

I'm not sure what I need to do.

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)

尝试

<my-input v-model="myModel2" @input="value => something = value" />

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>

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM