13

我有一个第 3 方输入组件(一个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 方法更清洁的方法。现在我的数据在 2 个地方重复 + 所有额外的(不需要的)事件处理......

我只想将反应数据直接从原始模板传递到 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 包装是我所做的。

4

2 回答 2

16

您需要将valueprop 向下转发到包装的组件,并将update事件转发备份(有关更多详细信息,请参见https://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'/>
于 2018-11-13T22:01:49.890 回答
1

I've create a mixin to simplify wrapping of a component.

You can see a sample here.

The mixin reuse the same pattern as you with "data" to pass the value and "watch" to update the value during a external change.

export default {
  data: function() {
    return {
      dataValue: this.value
    }
  },
  props: {
    value: String
  },
  watch: {
    value: {
      immediate: true,
      handler: function(newValue) {
        this.dataValue = newValue
      }
    }
  }
}

But on the wraping component, you can use "attrs" and "listeners" to passthrough all attributes and listener to your child component and override what you want.

<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>
于 2018-09-13T22:37:35.317 回答