首页 > 解决方案 > 如何使用 v-model 为输入 Vue 组件设置初始值

问题描述

我有以下组件:

Vue.component('email-input', {
  template: '#tmpl-email-input',
  name: 'email-input',
  delimiters: ['((', '))'],

  props: ['name', 'required', 'value'],

  data: () => ({
    suggestedEmail: '',
    email: '',
  }),

  methods: {
    onInput() {
      this.checkEmail();
      this.$emit('input', this.email);
    },

    checkEmail() {
      Mailcheck.run({
        email: this.email,

        suggested: suggestion => {
          this.suggestedEmail = suggestion.full;
        },

        empty: () => {
          this.suggestedEmail = '';
        },
      });
    },

    confirmSuggestion(confirm) {
      if (confirm) this.email = this.suggestedEmail;
      this.suggestedEmail = '';
    },
  },

  mounted() {
    this.checkEmail = _.debounce(this.checkEmail.bind(this), 1000);
  },
});

使用这个模板

<template id="tmpl-email-input">
  <div>
    <input
      type="email"
      class="form-control"
      :name="name || 'email'"
      :required="required"
      v-on:input="onInput"
      v-model="email"
    />
    <small class="email-correction-suggestion" v-if="suggestedEmail">
      Did you mean ((suggestedEmail))?
      <a href="#" class="btn-sm yes" @click.prevent="confirmSuggestion(true)">Yes</a>
      <a href="#" class="btn-sm no" @click.prevent="confirmSuggestion(false)">No</a>
    </small>
  </div>
</template>

<!-- Lodash from GitHub, using rawgit.com -->
<script src="https://cdn.rawgit.com/lodash/lodash/4.17.4/dist/lodash.min.js"></script>

<!-- Mailcheck: https://github.com/mailcheck/mailcheck -->
<script src="/js/lib/mailcheck.js"></script>

<script src="/js/views/partials/email_input.js"></script>

我用它来称呼它

<email-input name="email" required></email-input>

我想为此电子邮件输入设置一个初始值,例如

<email-input name="email" required value="test@test.com"></email-input>

并在输入中显示。

我以为我可以通过简单地将电子邮件设置为数据中的 this.value 来做到这一点,但这无济于事。我怎样才能做到这一点?

标签: vue.js

解决方案


有一个value prop,但你根本没有使用它!因此,您传递的值并不重要value prop:它不会被使用。

我认为您想要实现的是公开一个类似于input组件公开的 API。可以做到这一点,并且在 docs 中有详细说明

Vue 处理v-model绑定的做法是假设组件将发出一个input事件,并将新值作为$event. 它还将向下传递给组件一个值到value prop. 因此,只要您定义 avalue prop并发出input事件,Vue 就会自动处理这种 2-way 绑定。

问题是您的组件充当底层input组件的中间件,但它传递的是不同的绑定而不是转发它。

将其转换为您的组件,您不应该使用v-model传递emailinput组件,而是结合:value@input绑定:您将组件传递value propemail-input组件value prop,并且作为组件的事件input处理程序,您应该只发出另一个事件与相同的有效载荷。inputinputinput$event

模板:

<template id="tmpl-email-input">
  <div>
    <input
      type="email"
      class="form-control"
      :name="name || 'email'"
      :required="required"
      :value="value"
      @input="onInput($event.target.value)"
    />
    <small class="email-correction-suggestion" v-if="suggestedEmail">
      Did you mean ((suggestedEmail))?
      <a href="#" class="btn-sm yes" @click.prevent="confirmSuggestion(true)">Yes</a>
      <a href="#" class="btn-sm no" @click.prevent="confirmSuggestion(false)">No</a>
    </small>
  </div>
</template>

<!-- Lodash from GitHub, using rawgit.com -->
<script src="https://cdn.rawgit.com/lodash/lodash/4.17.4/dist/lodash.min.js"></script>

<!-- Mailcheck: https://github.com/mailcheck/mailcheck -->
<script src="/js/lib/mailcheck.js"></script>

<script src="/js/views/partials/email_input.js"></script>

请注意从@input="onInput"到的更改,@input="onInput($event.target.value)"以便我们可以访问onInput方法中的新值。

零件:

Vue.component('email-input', {
  template: '#tmpl-email-input',
  name: 'email-input',
  delimiters: ['((', '))'],

  props: ['name', 'required', 'value'],

  data: () => ({
    suggestedEmail: ''
  }),

  methods: {
    onInput(newValue) {
      this.$emit('input', newValue);
      this.checkEmail();
    },

    checkEmail() {
      Mailcheck.run({
        email: this.value,

        suggested: suggestion => {
          this.suggestedEmail = suggestion.full;
        },

        empty: () => {
          this.suggestedEmail = '';
        },
      });
    },

    confirmSuggestion(confirm) {
      if (confirm) this.$emit('input', this.suggestedEmail);
      this.suggestedEmail = '';
    },
  },

  mounted() {
    this.checkEmail = _.debounce(this.checkEmail.bind(this), 1000);
  },
});

注意方法的变化:现在它接受一个带有新值的参数,并在检查电子邮件地址之前onInput发出一个input带有该值的事件。它是按此顺序发出的,以确保我们在检查地址之前已经同步了绑定的值。value

还要注意方法的变化:它只是发出一个事件,confirmSuggestion而不是更新属性。email datainput

这是解决这个问题的关键:旧的实现迫使我们有两个不同的变量:一个是父组件可以传递一个值,另一个email-input可以修改以存储选择的建议。

如果我们只是将选择的建议作为常规更改发出,那么我们可以摆脱email变量并只使用一个绑定。


建议与问题完全无关:您可以直接使用 debouncemethods来代替mounted钩子上的方法:

Vue.component('email-input', {
      template: '#tmpl-email-input',
      name: 'email-input',
      delimiters: ['((', '))'],

      props: ['name', 'required', 'value'],

      data: () => ({
        suggestedEmail: ''
      }),

      methods: {
        onInput(newValue) {
          this.$emit('input', newValue);
          this.checkEmail();
        },

        checkEmail: _.debounce(function () {
          Mailcheck.run({
            email: this.value,

            suggested: suggestion => {
              this.suggestedEmail = suggestion.full;
            },

            empty: () => {
              this.suggestedEmail = '';
            },
          });
        }, 1000),

        confirmSuggestion(confirm) {
          if (confirm) this.$emit('input', this.suggestedEmail);
          this.suggestedEmail = '';
        },
      }
    });

Lodash 将负责this将底层函数绑定到this调用 debounced 函数的函数。


推荐阅读