【问题标题】:v-model on custom Vue component not changing value on input自定义 Vue 组件上的 v-model 不会更改输入值
【发布时间】:2021-03-19 01:38:44
【问题描述】:

我正在尝试创建一个 customCombobox 组件,它像普通的 v-combobox 一样工作,并添加一个 - 在用户按下 tab 键后,它将自动选择第一个选项(如果有的话)。

到目前为止,我所做的看起来不错,但此字段上的 v-model 不起作用(始终是 null)。

<template>
  <v-combobox ref="combobox" :rules="rules"
              @keydown.tab.prevent="selectFirst"
              :value="innerValue" :label="label"
              :items="items"

  >

  </v-combobox>
</template>
<script>
module.exports = {
  props: ['value', 'label', 'items', 'rules'],
  data() {
    return {
      innerValue:null,
    }
  },
  watch:{
    value(_new){
       this.innerValue = _new
      this.$emit('input',[_new])
      this.$emit('change')
    }
  },
  methods: {
    selectFirst() {
      var combobox = this.$refs.combobox
      var filteredItems = combobox.filteredItems
      if (filteredItems.length){
          this.innerValue = filteredItems[0]
      }
    }
  },
  computed: {

  }
}
</script>

你知道为什么吗?

【问题讨论】:

    标签: javascript vue.js vue-component vuetify.js vue-events


    【解决方案1】:

    您可以在自定义组件中使用计算设置器来处理来自父级的v-model,并将其传递给它自己的子级v-combobox

    自定义组件:

    <v-combobox v-model="selected" v-bind="$attrs"></v-combobox>
    
    computed: {
      selected: {
        get() {
          return this.value;
        },
        set(val) {
          this.$emit('input', val);
        }
      }
    }
    

    使用v-bind="$attrs" 也会从父级传递所有道具。这是一个演示:

    Vue.component('comp', {
      props: ['value'],
        template: `
        <v-combobox v-model="selected" v-bind="$attrs"></v-combobox>
      `,
      computed: {
        selected: {
          get() {
            return this.value;
          },
          set(val) {
            this.$emit('input', val);
          }
        }
      }
    })
    
    new Vue({
      el: '#app',
      vuetify: new Vuetify(),
      data() {
        return {
          selected: 'Vue',
          label: 'This is my label',
          rules: ['These are my rules'],
          items: ['Programming', 'Design', 'Vue', 'Vuetify']
        }
      }
    })
    #app {
      padding: 48px;
    }
    <div id="app">
      <v-app id="inspire">
        Selected in parent: {{ selected }}
        <comp
             v-model="selected"
             :label="label"
             :items="items"></comp>
      </v-app> 
    </div>
    
    <link href="https://fonts.googleapis.com/css?family=Roboto:100,300,400,500,700,900" rel="stylesheet">
    <link href="https://cdn.jsdelivr.net/npm/@mdi/font@4.x/css/materialdesignicons.min.css" rel="stylesheet">
    <link href="https://cdn.jsdelivr.net/npm/vuetify@2.x/dist/vuetify.min.css" rel="stylesheet">
    <script src="https://cdn.jsdelivr.net/npm/vue@2.x/dist/vue.js"></script>
    <script src="https://cdn.jsdelivr.net/npm/vuetify@2.x/dist/vuetify.js"></script>

    【讨论】: