【问题标题】:How to bind v-model in VueJS component如何在 VueJS 组件中绑定 v-model
【发布时间】:2019-02-07 08:46:33
【问题描述】:

我是 Vue 的新手,所以我尝试使用 Vuetify 创建一个 Input Date Picker

这是我的代码:

Codepen

问题是,当我在选择器中选择日期时,控制台中出现错误:

[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'

这是创建该组件的正确方法吗?

【问题讨论】:

    标签: vue.js vuejs2 vue-component vuetify.js


    【解决方案1】:

    如错误所述,您无法更改子项的道具。这是因为 Vue 使用了这个父子流:

    通过这种结构,您可以确保父母的数据是唯一的真实来源。 为了更改数据,您需要将其发送给父级。你的例子中几乎有它。您需要为v-model 发出input 来同步更改,而不是发出change 事件。

    当您看到docs 中的示例时,这一点会更加清楚:

    <input v-model="searchText">
    

    确实是一样的:

    <input
      v-bind:value="searchText"
      v-on:input="searchText = $event.target.value"
    >
    

    但是,从 vue 2.3.0 开始,您现在可以通过 .sync modifier 对 props 进行更改

    Vue.component('date-picker', {
        props: ['label'],
        data: () => ({
            date: null,
            dateFormatted: null,
            open: false
        }),
        created() {
            this.date = this.$value;
        },
        methods: {
            formatDate (date) {
                if (!date) return null
                const [year, month, day] = date.split('-')
                return `${day}/${month}/${year}`
            },
            parseDate (date) {
                if (!date) return null
                const [day, month, year] = date.split('/')
                return `${year}-${month.padStart(2, '0')}-${day.padStart(2, '0')}`
            },
            update() {
                this.$emit('input', this.dateFormatted);
            }
        },
        watch: {
            date (val) {
                this.dateFormatted = this.formatDate(this.date)
            },
            dateFormatted(val) {
                this.update();
            }
        },
        template:`
            <v-menu
                ref="open"
                :close-on-content-click="false"
                v-model="open"
                :nudge-right="40"
                lazy
                transition="scale-transition"
                offset-y
                full-width
                >
                <v-text-field
                    slot="activator"
                    v-model="dateFormatted"
                    :label="label"
                    placeholder="dia/mês/ano"
                    @blur="date = parseDate(dateFormatted)"
                ></v-text-field>
                <v-date-picker v-model="date" no-title @input="open = false"></v-date-picker>
            </v-menu>
        `
    });
    
    Vue.config.productionTip = false;
    Vue.config.devtools=false
    
    new Vue({
      el: '#app',
      data: () => ({
        myDate: '2018-09-01'
      })
    });
    <link href="https://cdn.jsdelivr.net/npm/vuetify@1.1.4/dist/vuetify.min.css" rel="stylesheet"/>
    <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/vuetify/1.2.0/vuetify.min.js"></script>
    
    
    <div id="app">
      <v-app>
         <v-flex xs24>
           <date-picker label="Select a date" v-model="myDate"></date-picker>
           <br>
           Current date: {{myDate}}
        </v-flex>
      </v-app>
    </div>

    【讨论】:

    • 感谢您的回答,但在您的代码中,输入时未选择初始日期值 (2018-09-01)!
    • 已解决,codepen.io/betonetotbo/pen/RYpeKv。我刚刚添加了value 属性,它有效,对吗?
    • 哦,是的!我的坏