【问题标题】:vue.js wrapping components which have v-modelsvue.js 包装具有 v-models 的组件
【发布时间】:2018-11-16 09:07:21
【问题描述】:

我有一个第 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 包装是我的工作。

【问题讨论】:

    标签: vue.js nested components v-model


    【解决方案1】:

    您需要将value prop 向下转发到被包装的组件,并将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'/>
    

    【讨论】:

      【解决方案2】:

      我创建了一个 mixin 来简化组件的包装。

      您可以查看示例here

      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>
      

      【讨论】:

        猜你喜欢
        • 2017-11-14
        • 2018-06-04
        • 1970-01-01
        • 1970-01-01
        • 2021-03-30
        • 1970-01-01
        • 2017-04-14
        • 2018-02-08
        • 1970-01-01
        相关资源
        最近更新 更多