vue 自定义组件使用v-model

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了vue 自定义组件使用v-model相关的知识,希望对你有一定的参考价值。

参考技术A v-model 是 Vue2 中唯一支持双向绑定的指令,用于表单控件绑定,但不代表它只能用在表单控件之上。在文档 使用自定义事件的表单输入组件 一节中提到了, v-model 其实是个语法糖。

这不过是以下示例的语法糖:

也就是说,你只需要在组件中声明一个name为value的props,并且通过触发input事件传入一个值,就能修改这个value。

查看详情: demo
demo里我保留了一些测试的东西,希望你能看的明白

如果绑定多个值的话,建议我们用object对象类型,Array数组类型,也就是说我们接收的value类型需要改变下。

props的验证类型建议也看看: props的验证类型

Vue:从自定义组件派生的自定义组件中的 v-model 和输入事件

【中文标题】Vue:从自定义组件派生的自定义组件中的 v-model 和输入事件【英文标题】:Vue: v-model and input event in custom component derived of a custom component 【发布时间】:2018-10-03 23:51:09 【问题描述】:

我有一个自定义输入,我在其中接收一个值道具并在输入事件上发出一个输入事件。我可以毫无问题地使用此自定义输入与模型,现在我正在创建一个自定义密码输入,我将其初始化为自定义输入,但我无法使用值和输入事件处理程序绑定模型(将它们传递给自定义输入) .我该如何处理?

自定义输入:

我的程序模型 > 自定义输入(值和输入事件处理程序):有效 我的程序模型 > 自定义密码(值和输入事件处理程序)> 自定义输入:不起作用

代码:

Input.vue

<template>
    <div class="form-group">

      <label for="" v-if="typeof label !== 'undefined'"> label </label>

      <!-- GROUP  -->
      <template v-if="isGroup">
        <div class="input-group">
          <!-- PREPEND  -->
          <div v-if="hasPrepend" class="input-group-prepend"
              :class="'inside bg-transparent' : prependInside, 'pointer': prependPointer"
              @click="clickPrepend">

            <span class="input-group-text"
                  :class="'bg-transparent' : prependInside">

              <i  aria-hidden="true"
                  v-if="prependType === 'icon'"
                  :class="'fa fa-' + prependContent"></i>

              <template v-if="prependType === 'text'"> prependContent </template>
            </span>

          </div>

          <!-- INPUT  -->
          <input  class="form-control"
              :type="type"
              :class="generatedInputClass"
              :readonly="readonly"
              :disabled="disabled"
              :value="value"
              @input="inputEvent"
              @change="onChange">

          <!-- APPEND  -->
          <div v-if="hasAppend" class="input-group-append"
              :class="'inside bg-transparent' : appendInside, 'pointer': appendPointer"
              @click="clickAppend">

            <span class="input-group-text"
                  :class="'bg-transparent' : appendInside">

              <i  aria-hidden="true"
                  v-if="appendType === 'icon'"
                  :class="'fa fa-' + appendContent"></i>

              <template v-if="appendType === 'text'"> appendContent </template>

            </span>

          </div>
      </div>
      </template>

      <!-- INPUT  -->
      <template v-else>
        <input  class="form-control"
              :type="type"
              :class="generatedInputClass"
              :readonly="readonly"
              :disabled="disabled"
              :value="value"

              @input="inputEvent"
              @change="onChange"
              >
      </template>

      <small  class="form-text"
              v-if="typeof helpText !== 'undefined'"
              :class="generatedHelperClass">
         helpText 
      </small>

    </div>
</template>

<script>
export default 
  name: 'InputGroup',
  props: 
    value: String,
    label: String,
    helpText: String,
    size: String,
    prependContent: String,
    appendContent: String,
    prependType: 
      type: String,
      default: 'icon',
    ,
    appendType: 
      type: String,
      default: 'icon',
    ,
    prependInside: 
      type: Boolean,
      default: false,
    ,
    appendInside: 
      type: Boolean,
      default: false,
    ,
    prependPointer: 
      type: Boolean,
      default: false,
    ,
    appendPointer: 
      type: Boolean,
      default: false,
    ,
    readonly: 
      type: Boolean,
      default: false,
    ,
    disabled: 
      type: Boolean,
      default: false,
    ,
    type: 
      type: String,
      default: 'text',
    ,
    valid: 
      type: Boolean,
      default: null,
    ,
  ,
  watch: 
    valid() 

    ,
  ,
  computed: 
    isGroup() 
      return this.hasPrepend || this.hasAppend;
    ,
    hasPrepend() 
      return typeof this.prependContent !== 'undefined';
    ,
    hasAppend() 
      return typeof this.appendContent !== 'undefined';
    ,
    generatedInputClass() 
      const size = typeof this.size !== 'undefined' ? `form-control-$this.size` : '';
      let valid = '';
      if (this.valid !== null) 
        valid = this.valid ? 'is-valid' : 'is-invalid';
      
      return `$size $valid`;
    ,
    generatedHelperClass() 
      let valid = 'text-muted';
      if (this.valid !== null) 
        valid = this.valid ? 'valid-feedback' : 'invalid-feedback';
      
      return `$valid`;
    ,
  ,
  methods: 
    inputEvent(e) 
      this.$emit('input', e.target.value);
    ,
    clickPrepend(e) 
      this.$emit('click-prepend', e);
    ,
    clickAppend(e) 
      this.$emit('click-append', e);
    ,
    onChange(e) 
      this.$emit('change', this.value, e);
    ,
  ,
;
</script>

Password.vue

<template>
<div>

  <app-input
              :label="label"
              :type="type"
              prepend-content="lock"
              :append-content="passwordIcon"
              :append-inside="true"
              :append-pointer="true"
              @click-append="tooglePassword"
              :value="value"
              @input="inputEvent">
  </app-input>
</div>
</template>

<script>
import Input from './Input';

export default 
  name: 'Password',
  components: 
    appInput: Input,
  ,
  props: 
    value: String,
    label: 
      type: String,
      default: 'Contraseña',
    ,
    readonly: 
      type: Boolean,
      default: false,
    ,
    disabled: 
      type: Boolean,
      default: false,
    ,
    valid: 
      type: Boolean,
      default: null,
    ,
  ,
  data() 
    return 
      pass: '',
      type: 'password',
    ;
  ,
  computed: 
    passwordIcon() 
      return this.type === 'password' ? 'eye' : 'eye-slash';
    ,
  ,
  methods: 
    tooglePassword() 
      this.type = this.type === 'password' ? 'text' : 'password';
    ,
    inputEvent(e) 
      this.$emit('input', e.target.value);
    ,
  ,
;
</script>

【问题讨论】:

【参考方案1】:

问题是你的Password 监听app-input 组件的input 事件,它的值实际字符串值已经,而不是元素(你必须调用@ 987654325@获取字符串值)

换句话说,在 Password.vue 中,而不是:

inputEvent(e) 
  this.$emit('input', e.target.value);
,

做:

inputEvent(e) 
  this.$emit('input', e);
,

CodeSandbox demo here.

【讨论】:

谢谢,现在我在 1 小时后弄明白了,但谢谢 :)

以上是关于vue 自定义组件使用v-model的主要内容,如果未能解决你的问题,请参考以下文章

Vue:从自定义组件派生的自定义组件中的 v-model 和输入事件

vue 组件自定义v-model

vue框架之自定义组件中使用v-model

使用 v-model 自定义 Vue 组件

vue v-model 在自定义组件上的使用教程

vue v-model 在自定义组件上的使用教程