Vue.js包装具有v-model的组件

15

我有一个第三方输入组件(一个vuetify v-text-field)。

为了验证的原因,我更喜欢将此组件包装在自己的组件中。

我的TextField.vue

<template>
    <v-text-field
            :label="label"
            v-model="text"
            @input="onInput"
            @blur="onBlur"
            :error-messages="this.getErrors(this.validation, this.errors)"
    ></v-text-field>
</template>

<script>
    import VTextField from "vuetify/es5/components/VTextField";
    import {vuelidateErrorsMixin} from '~/plugins/common.js';
    export default {
        name: "TextField",
        props: ['label', 'value', 'validation', 'errors'],
        mixins: [vuelidateErrorsMixin], //add vuelidate
        data: function() {
            return {
                'text': this.value
            }
        },
        components: {
            VTextField
        },
        methods : {
            onInput: function(value) {
                this.$emit('input', value);
                this.validation.$touch();
            },
            onBlur: function() {
                this.validation.$touch();
            }
        },
        watch: {
            value: {
                immediate: true,
                handler: function (newValue) {
                    this.text = newValue
                }
            }
        }
    }
</script>

被用于另一个组件中的内容

<template> 
 ...   
  <TextField v-model="personal.email" label="Email" 
        :validation="$v.personal.email" :errors="[]"/> 
   ... 
</template> 
<script> 
      ...imports etc. 
      export default {   ...     
          data: function() {
              return {
                  personal: {
                      email: '',
                      name: ''
                  }
            }      
      },      
      components: [ TextField ] 
    } 
</script>
这个方法可以正常工作,但我想知道是否有更加简洁的方法来避免重复整个v-model的过程。现在我的数据在两个地方重复,还有很多额外(不必要的)事件处理... 我只想直接将响应式数据传递到原始模板中的v-text-field中。我的TextField实际上根本不需要访问那些数据 - 只需被通知文本已更改(通过@input,@blur处理程序完成)。我不希望使用VUEX,因为它自己处理输入/表单时存在问题... 更接近这样的东西...
<template>
    <v-text-field
            :label="label"
            v-model="value" //?? SAME AS 'Mine'
            @input="onNotify"
            @blur="onNotify"
            :error-messages="this.getErrors(this.validation, this.errors)"
    ></v-text-field>
</template>

<script>
    import VTextField from "vuetify/es5/components/VTextField";
    import {vuelidateErrorsMixin} from '~/plugins/common.js';
    export default {
        name: "TextField",
        props: ['label', 'validation', 'errors'], //NO VALUE HERE as cannot use props...
        mixins: [vuelidateErrorsMixin], //add vuelidate
        components: {
            VTextField
        },
        methods : {
            onNotify: function() {
                this.validation.$touch();
            }
        },
    }
</script>

我找不到任何能够做到这一点的东西。

使用props + v-model包装是我所做的。

2个回答

21

你需要将 value 属性向下传递到包装的组件,并将 update 事件向上转发(有关更多详细信息,请参见 https://v2.vuejs.org/v2/guide/components.html#Using-v-model-on-Components):

<template>
  <wrapped-component
    :value='value'
    @input="update"
  />
</template>

<script>
  import wrappedComponent from 'wrapped-component'
  
  export default {
    components: { 'wrapped-component': wrappedComponent },
    props: ['value'],
    methods: {
      update(newValue) { this.$emit('input', newValue); }
    }
  }
</script>

别的地方:

<my-wrapping-component v-model='whatever'/>

注意,在Vue 3中这些名称已更改:prop: value -> modelValue 和 event: input -> update:modelValue - Markus Weninger

1
我创建了一个mixin来简化组件的包装。
你可以在这里看到一个示例。
该mixin重用与“data”传递值和“watch”在外部更改期间更新值相同的模式。
export default {
  data: function() {
    return {
      dataValue: this.value
    }
  },
  props: {
    value: String
  },
  watch: {
    value: {
      immediate: true,
      handler: function(newValue) {
        this.dataValue = newValue
      }
    }
  }
}

但是在包装组件上,您可以使用“attrs”和“listeners”将所有属性和监听器传递给子组件,并覆盖您想要的内容。

<template>
  <div>
    <v-text-field
        v-bind="$attrs"
        solo
        @blur="onBlur"
        v-model="dataValue"
        v-on="$listeners" />
  </div>
</template>

<script>
import mixin from '../mixins/ComponentWrapper.js'

export default {
  name: 'my-v-text-field',
  mixins: [mixin],
  methods: {
    onBlur() {
      console.log('onBlur')
    }
  }
}
</script>

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接