Vue component v-model with input handler

依然范特西╮ 提交于 2021-02-19 07:31:12

问题


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

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!