【问题标题】:Vue JS prop error for value on radio button with v-model and v-bind="$attrs"带有 v-model 和 v-bind="$attrs" 的单选按钮上的值的 Vue JS 道具错误
【发布时间】:2019-09-20 03:53:35
【问题描述】:

我遇到了一些我无法理解的奇怪行为。

我有一个简单的单选按钮组件,用作实际单选按钮的“包装器”。

在这个组件上,我有 inheritAttrs: false 并在元素本身上使用 v-bind="$attrs",所以我可以使用 v-model 和 value 等。

但是,在选择单选按钮时,会抛出一个错误,即 prop 值无效(因为它是一个事件而不是字符串),有趣的是,我注意到在初始渲染时,在 Vue Devtools 中 value prop 是空白的。

我只是想让这些单选按钮使用所选单选按钮的字符串值更新location 的父级数据对象值。

我无法弄清楚我到底哪里出错了。非常感谢任何帮助。

问题的示例项目: https://codesandbox.io/embed/m40y6y10mx

FormMain.vue

<template>
  <div>
    <p>Location: {{ location }}</p>
    <form-radio
      id="location-chicago"
      v-model="location"
      value="Chicago"
      name="location"
      label="Chicago"
      @change="changed"
    />
    <form-radio
      id="location-london"
      v-model="location"
      value="London"
      name="location"
      label="London"
      @change="changed"
    />
  </div>
</template>

<script>
import FormRadio from "./FormRadio.vue";

export default {
  name: "FormMain",
  components: {
    FormRadio
  },
  data() {
    return {
      location: ""
    };
  },
  methods: {
    changed(e) {
      console.log("Change handler says...");
      console.log(e);
    }
  }
};
</script>

FormRadio.vue

<template>
  <div>
    <label :for="id">
      {{ label }}
      <input
        :id="id"
        type="radio"
        :value="value"
        v-on="listeners"
        v-bind="$attrs"
      >
    </label>
  </div>
</template>

<script>
export default {
  name: "FormRadio",
  inheritAttrs: false,
  props: {
    id: {
      type: String,
      required: true
    },
    label: {
      type: String,
      required: true
    },
    value: {
      type: String,
      required: true
    }
  },
  computed: {
    listeners() {
      return {
        ...this.$listeners,
        change: event => {
          console.log("Change event says...");
          console.log(event.target.value);
          this.$emit("change", event.target.value);
        }
      };
    }
  }
};
</script>

【问题讨论】:

  • 奇怪的是你同时设置了v-model 和value - v-model 应该是值的真实来源
  • 但是我如何指定每个单选按钮都有自己的值来设置?否则你会怎么做?
  • 要建立一个示例答案...
  • 谢谢。如果您可以使用 Codesandbox,那就太好了。
  • 您如何尝试在 2 个不同的元素上使用相同的 v-model 有点令人困惑,因为它会决定两个元素的值

标签: javascript vue.js


【解决方案1】:

我从子组件调用中完全删除了 v-model(这是冲突的);

<form-radio
  id="location-chicago"
  value="Chicago"
  name="location"
  label="Chicago"
  @change="changed"
/>
<form-radio
  id="location-london"
  value="London"
  name="location"
  label="London"
  @change="changed"
/>

然后我更新了您更改的方法以包括设置位置变量

methods: {
  changed(e) {
    console.log("Change handler says...");
    console.log(e);
    this.location = e;
  }
}

更新:链接到更新的CodeSandbox

【讨论】:

  • 所以我猜你是说手动执行此操作? v-model 应该可以工作...它以这种方式与单个文本输入一起工作。如果我不为单选按钮使用包装器组件并且只是将它们放在具有相同属性的顶层,它甚至可以工作。可能是一个错误?
  • 可能。我对此知之甚少,不能公平。我无法向您展示可行的解决方案,因为我无法弄清楚如何分叉您的示例,我只能建议您尝试上面的编辑,看看它对您是否比对我更有意义。
  • 这在技术上是可行的……但我们失去了 v-model 为我们做这件事的好处。我想我想避免手动同步数据中的属性。
  • 我想如果location 设置为“芝加哥”,使用您的方法,您将如何防止它也适用于“伦敦”?我想这又回到了@DerekPollard 所说的
【解决方案2】:

编辑

找到了this 整洁的文章,描述了组件的model 属性。基本上,它允许您自定义v-model 的工作方式。使用它,FormMain.vue 不必更改。只需从 FormRadio 中删除 value 属性,然后添加带有您自己定义的模型属性

查看更新的codepen:

FormRadio 脚本

<script>
export default {
  name: "FormRadio",
  inheritAttrs: false,
  props: {
    id: {
      type: String,
      required: true
    },
    label: {
      type: String,
      required: true
    }
  },
  // customize the event/prop pair accepted by v-model
  model: {
    prop: "radioModel",
    event: "radio-select"
  },
  computed: {
    listeners() {
      return {
        ...this.$listeners,
        change: event => {
          console.log("Change event says...");
          console.log(event.target.value);
          // emit the custom event to update the v-model value
          this.$emit("radio-select", event.target.value);
          // the change event that the parent was listening for
          this.$emit("change", event.target.value);
        }
      };
    }
  }
};
</script>

编辑前:

如果存在v-model,Vue 似乎会忽略value 绑定属性。我通过为 radio-value 之类的值使用自定义属性来解决这个问题。

FormMain.vue

<form-radio
  id="location-chicago"
  v-model="location"
  radio-value="Chicago"
  name="location"
  label="Chicago"
  @change="changed"
/>
<form-radio
  id="location-london"
  v-model="location"
  radio-value="London"
  name="location"
  label="London"
  @change="changed"
/>

input 事件处理程序将更新 v-model。

FormRadio.vue

<template>
  <div>
    <label :for="(id) ? `field-${id}` : false">
      {{ label }}
      <input
        :id="`field-${id}`"
        type="radio"
        :value="radioValue"
        v-on="listeners"
        v-bind="$attrs"
      >
    </label>
  </div>
</template>

<script>
export default {
  name: "FormRadio",
  inheritAttrs: false,
  props: {
    id: {
      type: String,
      required: true
    },
    label: {
      type: String,
      required: true
    },
    radioValue: {
      type: String,
      required: true
    }
  },
  computed: {
    listeners() {
      return {
        ...this.$listeners,
        input: event => {
          console.log("input event says...");
          console.log(event.target.value);
          this.$emit("input", event.target.value);
        },
        change: event => {
          console.log("Change event says...");
          console.log(event.target.value);
          this.$emit("change", event.target.value);
        }
      };
    }
  }
};
</script>

见forked codepen

【讨论】:

  • 我明白了。谢谢你这个作品。我猜这是 Vue 的错误吗?
  • 我认为这是设计使然。据报道,组件包装了其他本机输入类型。我在 GitHub 上找到了这个 issue
猜你喜欢
  • 2020-03-31
  • 2020-09-13
  • 1970-01-01
  • 2017-04-16
  • 1970-01-01
  • 2017-07-04
  • 2018-05-22
  • 2020-12-03
  • 2018-08-31
相关资源
最近更新 更多