【问题标题】:How to make Vue component work with v-model preserving value type?如何使 Vue 组件与 v-model 保留值类型一起工作?
【发布时间】:2018-06-26 08:53:16
【问题描述】:

问题

当我在 HTML <select> 上有 v-model 时,v-model 将给定属性设置为该值的选定值保留类型 - 如果我将数字绑定到 <option>,则设置模型属性到数字,如果我绑定一个对象,它就会被设置为那个对象。

<script>
export default {
  data: {
    options: [5, 10, 15, 'text', { 'description': 'I am an Object' }],
  }
};
</script>

<template>
  <select v-model="model">
    <option
      v-for="option in options"
      :value="option"
    >
      {{ option }}
    </option>
  </select>
<template>

我有一个&lt;base-select&gt; 自定义组件,它为我包装了&lt;select&gt; 标签的用法。我正在尝试为它实现相同的 v-model 行为,但失败了,因为类型没有被保留 - 我一直返回字符串,即使我在绑定数字或对象时也是如此。

//// BaseSelect.vue

<script>
export default {
  props: {
    options: {
      type: Array,
      required: true
    },
    value: {
      required: true
    }
  },
};
</script>
<template>
  <select
    :value="value"
    @input="$emit('input', $event.target.value)"
  >
    <option
      v-for="option in options"
      :value="option"
    >
      {{ option }}
    </option>
  </select>
</template>

//// App.vue

<script>
  @import 'BaseSelect' from './BaseSelect';

  export default {
    components: {
      BaseSelect,
    },
    data: {
      options: [5, 10, 15, 'text', { 'description': 'I am an Object' }],
    }
  };
</script>
<template>
  <base-select
    v-model="model"
    :options="options"
  />
<template>

小提琴

这里是这种行为清晰可见的地方:http://jsfiddle.net/4o67pzLs/14/

第一个选择是保留绑定到模型的值类型,而另一个选择是始终将值设置为字符串。

问题

是否可以在自定义组件上实现v-model,这样可以保留类型?如果有,怎么做?

【问题讨论】:

    标签: javascript vue.js vue-component


    【解决方案1】:

    这是我们最终与@RobertKusznier 一起完成的方式:

    • 使用v-model将选择与组件的计算属性绑定
    • 为该计算属性定义 getter 和 setter
    • getter 返回组件的值
    • setter 发出更改事件

    它保留所选选项值的类型,并且不会改变组件的值。

    感谢@RobertKusznier,他建议我们没有改变组件的值。

    let baseSelect = {
    	props: {
      	options: {
        	type: Array,
          required: true
        },
        value: {
        	required: true
        }
      },
      
      computed: {
      	valueCopy: {
        	get() {
          	return this.value;
          },
          set(value) {
          	this.$emit('input', value);
          }
        }
      },
      
      template: `
      	<select
          v-model="valueCopy"
        >
          <option
            v-for="option in options"
            :value="option"
          >
            {{ option }}
          </option>
        </select>
      `,
    };
    
    new Vue({
    	el: '#app',
      components: {
      	baseSelect
      },
      data: {
      	model: 5,
        options: [5, 10, 15, 'text', new Date()]
      },
      template: `
        <div>
          <select v-model="model">
            <option
              v-for="option in options"
              :value="option">
                {{ option }}
            </option>
          </select>
          
          <base-select
            v-model="model"
            :options="options"
            :sister="10"
          />
          
          <p>model: {{ model }}</p>
          <p>typeof model: {{ typeof model }}</p>
        </div>
      `
    });
    <script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.16/vue.min.js"></script>
    <div id="app"></div>

    【讨论】:

    • 由于某种原因,它在我的Fiddle 中不起作用(我看到它在您的示例中起作用)。你知道为什么吗?
    • 在您的组件中,您在props 对象中添加了model 对象。将它移动到 baseSelect 对象的根目录,它应该可以工作:jsfiddle.net/23tLge6u
    • 真 :)。感谢您发现这一点。
    • 好的,我简化了代码,在组件设置中省略了modeljsfiddle.net/gswbfLde/20。在您的解决方案中唯一让我担心的是变异组件道具。过去,我在控制台中看到警告不要这样做。但在这段代码中,我看不到它们。我还在调查...
    • 是的,我在我的应用程序中尝试了相同的解决方案(不是在 JSFiddle 中)并收到了警告:[Vue warn]: Avoid mutating a prop directly since the value will be overwritten whenever the parent component re-renders. Instead, use a data or computed property based on the prop's value. Prop being mutated: "value"。我想避免这样的警告。我也同意这个警告,并认为改变道具不是一个干净的解决方案。
    猜你喜欢
    • 2021-12-14
    • 2020-08-19
    • 1970-01-01
    • 1970-01-01
    • 2019-02-14
    • 2021-06-17
    • 2021-08-11
    • 2019-04-30
    • 2021-12-30
    相关资源
    最近更新 更多